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
AI-Powered Network Security for Modern Web Applications
Penjaro provides intelligent, proactive network security for your web applications and APIs. It acts as a smart shield between your application and potential threats, analyzing incoming requests and outgoing responses using a sophisticated combination of:
- Rule-based detection
- Threat intelligence feeds
- AI-powered analysis (optional)
- 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 Choose 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: 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, NestJS, Koa, 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
Key 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
- 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.jsmodels - 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
# Install the core package
npm install penjaro-network-security-library-javascript
# Or with yarn
yarn add penjaro-network-security-library-javascript
# Install peer dependencies for your framework (e.g., Express)
npm install 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 featuresCore 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
- Analyzes incoming requests only
- Blocks malicious requests or passes legitimate ones to your application logic
- Ideal for securing existing applications without changing infrastructure
2. Proxy Mode (targetServer is provided)
- Acts as a reverse proxy
- Analyzes both incoming requests and outgoing responses
- Forwards valid requests to your target server
- Provides comprehensive protection including data leak prevention
- Requires Penjaro to run as a separate process or container
Quick Start Examples
Express (Middleware Mode)
import express from 'express';
import { createPenjaroProxy, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript';
const app = express();
const penjaroOptions: PenjaroConfigOptions = {
apiKey: process.env.PENJARO_API_KEY,
enableRateLimit: true,
enableThreatIntelCheck: true,
includeDefaultFireholFeed: true,
};
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();Express (Proxy Mode)
import express from 'express';
import { createPenjaroProxy, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript';
async function startProxy() {
try {
const penjaroOptions: PenjaroConfigOptions = {
apiKey: process.env.PENJARO_API_KEY,
targetServer: 'http://localhost:8080', // Your actual application server
enableRateLimit: true,
enableResponseAnalysis: true, // Enable response analysis
enableDataLeakChecks: true,
enableVerboseErrorChecks: true,
};
// Initialize Penjaro proxy
const penjaroProxy = await createPenjaroProxy(penjaroOptions);
// Create an Express app that just uses the proxy
const app = express();
app.use(penjaroProxy);
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Penjaro proxy running on port ${PORT}, forwarding to ${penjaroOptions.targetServer}`);
});
} catch (error) {
console.error("Failed to initialize Penjaro proxy:", error);
process.exit(1);
}
}
startProxy();Framework Integration Examples
NestJS
NestJS integration is easy and clean with Penjaro's dedicated adapter. Here's a complete example:
1. Create a Penjaro Module
// src/penjaro/penjaro.module.ts
import { Module, DynamicModule } from '@nestjs/common';
import { PenjaroService } from './penjaro.service';
import { PenjaroConfigOptions } from 'penjaro-network-security-library-javascript';
@Module({})
export class PenjaroModule {
static register(options: PenjaroConfigOptions): DynamicModule {
return {
module: PenjaroModule,
providers: [
{
provide: 'PENJARO_OPTIONS',
useValue: options,
},
PenjaroService,
],
exports: [PenjaroService],
};
}
}2. Create a Penjaro Service
// src/penjaro/penjaro.service.ts
import { Injectable, Inject, OnModuleInit, OnModuleDestroy, Logger } from '@nestjs/common';
import { createPenjaroProxy, PenjaroConfigOptions } from 'penjaro-network-security-library-javascript';
import { RequestHandler } from 'express';
@Injectable()
export class PenjaroService implements OnModuleInit, OnModuleDestroy {
private middleware: RequestHandler | null = null;
private redisClient: unknown | null = null;
private readonly logger = new Logger(PenjaroService.name);
private initializationPromise: Promise<void> | null = null;
constructor(
@Inject('PENJARO_OPTIONS') private readonly options: PenjaroConfigOptions,
) {}
async onModuleInit() {
this.initializationPromise = this.initialize();
await this.initializationPromise;
}
private async initialize() {
try {
this.logger.log('Initializing Penjaro middleware...');
this.middleware = (await createPenjaroProxy(
this.options,
)) as unknown as RequestHandler;
// Store redis client reference if it exists
if (this.options.redisClient) {
this.redisClient = this.options.redisClient;
}
this.logger.log('Penjaro middleware initialized successfully');
} catch (error) {
this.logger.error(`Failed to initialize Penjaro middleware: ${error.message}`);
throw error;
}
}
async onModuleDestroy() {
// Clean up redis connection if needed
if (
this.redisClient &&
typeof (this.redisClient as any).disconnect === 'function'
) {
try {
await (this.redisClient as any).disconnect();
this.logger.log('Redis client disconnected successfully');
} catch (error) {
this.logger.error(`Error disconnecting Redis client: ${error.message}`);
}
}
}
getMiddleware(): RequestHandler {
if (!this.middleware) {
throw new Error('Penjaro middleware not initialized');
}
return this.middleware;
}
}3. Create a Penjaro Middleware
// src/penjaro/penjaro.middleware.ts
import { Injectable, NestMiddleware, Logger } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { PenjaroService } from './penjaro.service';
@Injectable()
export class PenjaroMiddleware implements NestMiddleware {
private readonly logger = new Logger(PenjaroMiddleware.name);
constructor(private readonly penjaroService: PenjaroService) {}
use(req: Request, res: Response, next: NextFunction) {
try {
const middleware = this.penjaroService.getMiddleware();
middleware(req, res, (err?: any) => {
if (err) {
this.logger.error(`Penjaro middleware error: ${err.message}`);
return next(err);
}
next();
});
} catch (error) {
this.logger.error(`Failed to get Penjaro middleware: ${error.message}`);
next(error);
}
}
}4. Use in App Module
// src/app.module.ts
import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PenjaroModule } from './penjaro/penjaro.module';
import { PenjaroMiddleware } from './penjaro/penjaro.middleware';
@Module({
imports: [
PenjaroModule.register({
apiKey: process.env.PENJARO_API_KEY,
enableRateLimit: true,
rateLimitPoints: 5,
rateLimitDuration: 10, // 10 seconds
enableResponseAnalysis: true,
enableDataLeakChecks: true,
enableVerboseErrorChecks: true,
// Example custom rules
customRequestRulePatterns: {
xss: [/<script[^>]*>[\s\S]*?<\/script>/i],
sql: [/(\%27)|(\')|(\-\-)|(\%23)|(#)/i, /(\s|;|\/\*)+(select|union|insert|drop|delete|update|create|alter)/i],
},
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(PenjaroMiddleware)
.exclude('health') // Exclude health check endpoint
.forRoutes('*');
}
}Alternative NestJS with Adapter Factory
// src/app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { createPenjaroAdapter, Framework } from 'penjaro-network-security-library-javascript/dist/adapters';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule implements NestModule {
async configure(consumer: MiddlewareConsumer) {
const penjaroMiddleware = await createPenjaroAdapter(Framework.NESTJS, {
apiKey: process.env.PENJARO_API_KEY,
enableRateLimit: true,
rateLimitPoints: 10,
rateLimitDuration: 1,
});
consumer
.apply(penjaroMiddleware)
.forRoutes('*');
}
}Koa Example
import Koa from 'koa';
import { createPenjaroAdapter, Framework } from 'penjaro-network-security-library-javascript/dist/adapters';
const app = new Koa();
async function start() {
try {
const penjaroMiddleware = await createPenjaroAdapter(Framework.KOA, {
apiKey: process.env.PENJARO_API_KEY,
enableRateLimit: true,
enableThreatIntelCheck: true,
includeDefaultFireholFeed: true,
});
// Add Penjaro middleware
app.use(penjaroMiddleware);
// Add your routes
app.use(async (ctx) => {
ctx.body = 'Hello World';
});
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
} catch (error) {
console.error('Failed to initialize Penjaro middleware:', error);
process.exit(1);
}
}
start();Fastify Example
import Fastify from 'fastify';
import { createPenjaroAdapter, Framework } from 'penjaro-network-security-library-javascript/dist/adapters';
const fastify = Fastify({ logger: true });
async function start() {
try {
const penjaroPlugin = await createPenjaroAdapter(Framework.FASTIFY, {
apiKey: process.env.PENJARO_API_KEY,
enableRateLimit: true,
enableThreatIntelCheck: true,
});
// Register Penjaro plugin
await fastify.register(penjaroPlugin);
// Define routes
fastify.get('/', async (request, reply) => {
return { hello: 'world' };
});
// Start server
await fastify.listen({ port: 3000, host: '0.0.0.0' });
console.log(`Server running on ${fastify.server.address().port}`);
} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
}
start();Hapi Example
import Hapi from '@hapi/hapi';
import { createPenjaroAdapter, Framework } from 'penjaro-network-security-library-javascript/dist/adapters';
async function start() {
try {
const server = Hapi.server({
port: 3000,
host: 'localhost',
});
const penjaroPlugin = await createPenjaroAdapter(Framework.HAPI, {
apiKey: process.env.PENJARO_API_KEY,
enableRateLimit: true,
rateLimitPoints: 10,
rateLimitDuration: 1,
});
// Register Penjaro plugin
await server.register(penjaroPlugin);
// Define routes
server.route({
method: 'GET',
path: '/',
handler: (request, h) => {
return 'Hello World!';
},
});
// Start server
await server.start();
console.log(`Server running on ${server.info.uri}`);
} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
}
start();Configuration Reference
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 |
targetServer |
string |
undefined |
If set, enables Proxy Mode. If omitted, enables Middleware Mode |
aiModel |
tf.LayersModel or compatible |
null |
Pre-loaded TensorFlow.js model for AI analysis |
proxyConfig |
object |
{} |
Options passed to http-proxy-middleware (Proxy Mode only) |
enableRateLimit |
boolean |
true |
Enables basic IP-based rate limiting |
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) |
enableDataLeakChecks |
boolean |
true |
Enables checks for common PII/key patterns in responses |
enableVerboseErrorChecks |
boolean |
true |
Enables checks for stack traces/verbose errors in responses |
responseAnalysisMaxSize |
number |
1048576 (1MB) |
Maximum response body size to analyze |
responseAnalysisContentTypes |
string[] |
['application/json', 'text/html', ...] |
Content types to analyze |
blockUnsafeResponses |
boolean |
true |
Block responses that fail data leak or error checks |
replaceDefaultPatterns |
boolean |
false |
If true, custom patterns replace default ones |
customDataLeakPatterns |
RegExp[] |
[] |
Custom patterns to detect sensitive data leaks |
customVerboseErrorPatterns |
RegExp[] |
[] |
Custom patterns to detect verbose errors |
enableJa3Check |
boolean |
false |
Enables blocking based on TLS JA3 fingerprint |
ja3HeaderName |
string |
'X-JA3-Hash' |
Header name containing the JA3 hash |
badJa3Hashes |
string[] |
[...] |
List of malicious JA3 hashes to block |
enableGraphqlProtection |
boolean |
false |
Enables GraphQL-specific security checks |
graphqlMaxDepth |
number |
10 |
Maximum allowed GraphQL query nesting depth |
graphqlMaxComplexity |
number |
1000 |
Maximum allowed GraphQL query complexity |
graphqlBlockIntrospection |
boolean |
true |
Blocks GraphQL introspection queries |
graphqlBlockKeywords |
string[] |
[] |
Keywords to block in GraphQL arguments |
enableThreatIntelCheck |
boolean |
false |
Enables IP checking against threat feeds |
threatIntelFeedUrls |
string[] |
[] |
URLs for custom IP blocklist feeds |
threatIntelFetchIntervalMinutes |
number |
60 |
How often to refresh threat feeds |
includeDefaultTorFeed |
boolean |
false |
Include the Tor exit node list |
includeDefaultFireholFeed |
boolean |
false |
Include the FireHOL Level 1 blocklist |
includeDefaultFeodoFeed |
boolean |
false |
Include the Feodo Tracker IP blocklist |
includeDefaultCinsFeed |
boolean |
false |
Include the CINS Army List |
whitelistIps |
string[] |
[] |
IPs that should never be blocked |
excludePathsFromDataLeakCheck |
RegExp[] |
[] |
URL paths to exclude from data leak checks |
excludePathsFromErrorCheck |
RegExp[] |
[] |
URL paths to exclude from error checks |
redisClient |
RedisClientType |
undefined |
Pre-configured Redis client instance |
redisUrl |
string |
undefined |
Redis connection URL |
redisOptions |
object |
undefined |
Redis connection options |
disableDefaultRequestRules |
object |
{} |
Disable specific built-in rule categories |
customRequestRulePatterns |
object |
{} |
Add custom request rule patterns |
replaceDefaultRequestPatterns |
boolean |
false |
Replace default request patterns |
featureExtractor |
(req: Request) => number[] |
undefined |
Function to extract features for AI model |
aiAnalysisFailureMode |
'fail-open' | 'fail-closed' |
'fail-open' |
Behavior if AI analysis fails |
enableIncidentReporting |
boolean |
true |
Reports blocked requests to Penjaro API |
Advanced Features
AI Model Integration
Penjaro can use TensorFlow.js models to detect sophisticated attacks:
import * as tf from '@tensorflow/tfjs-node';
import { createPenjaroProxy } from 'penjaro-network-security-library-javascript';
import { Request } from 'express';
async function setupSecurityWithAI() {
// Load your pre-trained model
const model = await tf.loadLayersModel('file:///path/to/model/model.json');
// Define a feature extractor function
function extractFeatures(req: Request): number[] {
// Extract meaningful features from the request
const features = [
req.headers['content-length'] ? parseInt(req.headers['content-length'] as string, 10) : 0,
req.query ? Object.keys(req.query).length : 0,
// Add more features as needed
];
return features;
}
// Initialize Penjaro with AI capabilities
const penjaroMiddleware = await createPenjaroProxy({
apiKey: process.env.PENJARO_API_KEY,
aiModel: model,
featureExtractor: extractFeatures,
aiAnalysisFailureMode: 'fail-open', // Allow requests if AI fails
});
return penjaroMiddleware;
}Threat Intelligence Integration
Block requests from known malicious IP addresses:
const penjaroOptions = {
apiKey: process.env.PENJARO_API_KEY,
enableThreatIntelCheck: true,
includeDefaultTorFeed: true, // Block Tor exit nodes
includeDefaultFireholFeed: true, // Block IPs from FireHOL list
includeDefaultFeodoFeed: true, // Block Feodo botnet IPs
threatIntelFetchIntervalMinutes: 60, // Update hourly
whitelistIps: ['192.168.1.1'], // Never block these IPs
// Add your custom feeds
threatIntelFeedUrls: [
'https://your-organization.com/custom-blocklist.txt',
],
// Handle feed fetch errors
onThreatIntelError: (error) => {
console.error('Threat feed error:', error);
}
};GraphQL Protection
Prevent GraphQL-specific attacks:
const penjaroOptions = {
apiKey: process.env.PENJARO_API_KEY,
enableGraphqlProtection: true,
graphqlMaxDepth: 8, // Limit query nesting
graphqlMaxComplexity: 500, // Limit query complexity
graphqlBlockIntrospection: true, // Block schema introspection
graphqlBlockKeywords: [
'union all select', // SQL injection attempts
'../../', // Path traversal attempts
'exec(', // Command injection attempts
]
};Response Analysis (Proxy Mode)
Prevent data leaks in your application responses:
const penjaroOptions = {
apiKey: process.env.PENJARO_API_KEY,
targetServer: 'http://localhost:8080', // Enable proxy mode
enableResponseAnalysis: true,
enableDataLeakChecks: true,
enableVerboseErrorChecks: true,
// Exclude certain paths
excludePathsFromDataLeakCheck: [
/\/api\/auth\//i, // Auth endpoints may contain emails
/\/api\/users\/profile/i, // Profile endpoints may contain PII
],
// Add custom data leak patterns
customDataLeakPatterns: [
/company-secret-[a-z0-9]{10}/i, // Company specific secrets
],
// Add custom error patterns
customVerboseErrorPatterns: [
/Internal Server Error: [a-z0-9]/i,
/Database connection failed/i
]
};Redis Integration for Distributed Deployments
Share state across multiple application instances:
import { createClient } from 'redis';
import { createPenjaroProxy } from 'penjaro-network-security-library-javascript';
async function setupDistributedSecurity() {
// Initialize Redis client
const redisClient = createClient({
url: process.env.REDIS_URL || 'redis://localhost:6379',
});
await redisClient.connect();
// Initialize Penjaro with Redis
const penjaroMiddleware = await createPenjaroProxy({
apiKey: process.env.PENJARO_API_KEY,
redisClient, // Pass the connected client
enableRateLimit: true, // Rate limiting will use Redis
enableThreatIntelCheck: true // Threat intel will use Redis
});
return penjaroMiddleware;
}Performance Considerations
Response Analysis Performance Impact
Response analysis (Proxy Mode only) has the highest performance cost:
- Requires buffering responses in memory
- Increases latency slightly
- Breaks streaming responses
- Increases memory usage
If you're using streaming or have very large responses, consider:
const penjaroOptions = {
// ...other options...
enableResponseAnalysis: true,
// Limit analysis to smaller responses
responseAnalysisMaxSize: 512000, // 500KB max
// Only analyze these content types
responseAnalysisContentTypes: [
'application/json',
'text/html'
],
// Exclude high-volume endpoints
excludePathsFromDataLeakCheck: [
/\/api\/stream\//i,
/\/api\/download\//i
]
};Rate Limiting in Distributed Environments
For accurate rate limiting across multiple instances:
const penjaroOptions = {
// ...other options...
enableRateLimit: true,
rateLimitPoints: 100, // 100 requests
rateLimitDuration: 60, // per 60 seconds
redisUrl: process.env.REDIS_URL // Use Redis to share rate limit state
};Best Practices
Apply Early in Request Pipeline: Apply Penjaro middleware before routes and other middleware to catch threats early.
Environment-Based Configuration: Use different security settings for development and production:
const isProd = process.env.NODE_ENV === 'production';
const penjaroOptions = {
apiKey: process.env.PENJARO_API_KEY,
// Stricter settings in production
enableRateLimit: isProd,
enableThreatIntelCheck: isProd,
includeDefaultFireholFeed: isProd,
// GraphQL introspection in dev, blocked in prod
enableGraphqlProtection: true,
graphqlBlockIntrospection: isProd,
// More verbose logging in development
logLevel: isProd ? 'warn' : 'debug'
};- Health Checks: Always exclude health check endpoints from protection:
// NestJS
consumer
.apply(PenjaroMiddleware)
.exclude('health', 'metrics') // Exclude monitoring endpoints
.forRoutes('*');
// Express
app.use((req, res, next) => {
if (req.path === '/health' || req.path === '/metrics') {
return next();
}
penjaroMiddleware(req, res, next);
});- Custom Rules: Add application-specific security rules:
const penjaroOptions = {
// ...other options...
customRequestRulePatterns: {
// Custom pattern for detecting credit card numbers
pii: [/4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}/],
// Custom pattern for your specific business logic attacks
businessLogic: [/manipulate=true/i, /bypass=admin/i]
}
};- Whitelist Trusted IPs: Always whitelist your trusted sources:
const penjaroOptions = {
// ...other options...
whitelistIps: [
'10.0.0.0/8', // Internal network
'192.168.0.0/16', // Internal network
'172.16.0.0/12', // Internal network
'127.0.0.1', // Localhost
],
};Troubleshooting
Common Issues and Solutions
Middleware Not Blocking Attacks
- Verify the middleware is applied early in the request pipeline
- Check if the attacker's IP is in the whitelist
- Review and update rule patterns
High CPU/Memory Usage
- Reduce
responseAnalysisMaxSize - Exclude high-volume endpoints
- Increase
rateLimitPointsif legitimate traffic is high
- Reduce
Redis Connection Issues
- Ensure Redis connection string is correct
- Check Redis server health
- Confirm firewall rules allow the connection
Legitimate Requests Being Blocked
- Add IPs to
whitelistIps - Exclude specific patterns from checks
- Adjust rate limit settings
- Add IPs to
Logging and Debugging
Enable debug logging for troubleshooting:
const penjaroOptions = {
// ...other options...
logLevel: 'debug', // Options: 'error', 'warn', 'info', 'debug'
};API Key Management
The apiKey is required for Penjaro to validate configuration and report incidents. Obtain your key from the Penjaro dashboard or administrator.
Best practices for API key management:
Environment Variables: Never hardcode the API key
const penjaroOptions = { apiKey: process.env.PENJARO_API_KEY, // ...other options };
Secrets Management: Use a secure vault service in production
const apiKey = await secretsManager.getSecret('penjaro-api-key'); const penjaroOptions = { apiKey, // ...other options };
Key Rotation: Implement a process for regular key rotation
License
Currently UNLICENSED. Please contact the author for licensing inquiries.
Support and Contact
For support, feature requests, or bug reports, please contact:
- Author: Ugochukwu Nwajagu
- Repository: GitHub