Documentation

Everything you need to get septr running in your app.

Quick start

Septr runs in-process and reports what it detects to your dashboard. It takes about five minutes to wire up.

1. Get your API key

Create a free account and a project at app.septr.dev. The project API key is shown once at creation and can be copied or rotated later in the project's Settings. The key encodes the project id, so it's the only value you need to configure.

2. Install the middleware

$ npm install septr      # Node.js — Express, Next.js, Hono, Fastify
$ pip install septr      # Python — FastAPI, Flask

3. Add the key to your environment

Never hard-code it in source:

SEPTR_API_KEY=septr_live_...

4. Wrap your app

Express, for example — see framework guides for the rest:

import { createSeptr } from "septr/express"

app.use(createSeptr({
  apiKey: process.env.SEPTR_API_KEY
}))
Fail-open guarantee: If Septr ever throws, it logs the error and passes the request through. Your app never goes down because of its bodyguard.

5. Verify it's working

Restart your app and make one request. Within ~30 seconds the project appears as connected in your dashboard, and the logs show a handshake line:

[septr] Connected to project 'your-app' — handshake OK

No install needed to preview what septr finds: npx septr scan <your-app-url> scans a deployed app for exposed secrets, missing headers, and vulnerable dependencies.

Framework guides

Septr supports Express, Next.js, Hono, Fastify, Flask, FastAPI, Gin, net/http, and Streamlit (via CLI/network). Pick your framework:

Express Next.js Hono Fastify Flask FastAPI Gin net/http Streamlit

Express

import express from "express"
import { createSeptr } from "septr/express"

const app = express()

app.use(createSeptr({
  apiKey: process.env.SEPTR_API_KEY
}))

app.listen(3000)

Configuration

Pass options to createSeptr() to customize behavior. All engines are enabled by default.

OptionTypeDefaultDescription
apiKeystringenv SEPTR_API_KEYYour project API key
telemetrybooleantrueSend detections to the dashboard (set false to disable)
strictModebooleanfalseBlock requests instead of detecting
secretsbooleantrueSecret/PII detection + response scrubbing
bolabooleantrueBOLA/IDOR detection
rateLimitbooleantruePer-route rate limiting
inputSanitizebooleantrueSQLi/XSS/NoSQLi sanitization
ssrfbooleantrueSSRF heuristics
promptInjectionbooleantruePrompt-injection shielding
aiRateLimitbooleantrueRate limiting for AI endpoints
tamperbooleantrueBusiness-logic tamper detection
missingAuthbooleantrueMissing-auth detection
stripFieldsstring[][]Fields to strip from responses
telemetryUrlstringhttps://app.septr.dev/v1/eventsTelemetry endpoint
projectIdstringderived from keyProject id; auto-read from septr_live_* keys
remoteConfigbooleantruePoll backend for live config

Example with all options

app.use(createSeptr({
  apiKey: process.env.SEPTR_API_KEY,
  strictMode: false,
  secrets: true,
  bola: true,
  rateLimit: true,
  inputSanitize: true,
  ssrf: true,
  promptInjection: true,
  aiRateLimit: true,
  tamper: true,
  missingAuth: true,
  stripFields: ["password_hash", "ssn"],
  remoteConfig: true,
}))

Detection engines

Septr runs 12 detection engines in-process. Each one scans every request/response in memory and emits evidence to your dashboard.

Secrets (22 patterns)

Scans response bodies for leaked credentials. Matches against 22 patterns including:

  • OpenAI API keys (sk-)
  • Stripe keys (sk_live_, rk_live_)
  • AWS access keys (AKIA)
  • GitHub tokens (ghp_, gho_)
  • JWTs and private keys
  • Database connection strings

Matched values are replaced with [REDACTED] in the response.

BOLA / IDOR

Compares JWT claims (sub, user_id) against route parameters (:id, :userId). If a user tries to access another user's resource, the request is blocked with a 403.

GET /api/users/8812  Authorization: Bearer eyJ…
jwt.sub=4417 ≠ route.id=8812 → 403 Forbidden

SQLi / XSS

SQLi: 14 patterns — UNION SELECT, OR 1=1, DROP TABLE, WAITFOR DELAY, and more.

XSS: 17 patterns — <script>, onerror, javascript:, event handlers.

Both are detected in request bodies and query strings.

Prompt injection

24 jailbreak patterns including:

  • DAN / "Do Anything Now" prompts
  • Role overrides ("ignore previous instructions")
  • System prompt extraction attempts
  • Tool-call manipulation

SSRF

Blocks requests targeting internal resources:

  • Internal IPs: 127.0.0.0/8, 10.0.0.0/8, 192.168.x.x
  • Cloud metadata: 169.254.169.254
  • Dangerous protocols: file://, gopher://

Rate limiting

Sliding-window rate limiting per IP and route. Default tiers:

Endpoint typeLimit
General60 requests/min
Auth endpoints10 requests/min
AI endpoints5 requests/min

Static assets (/static/, /_next/, images, CSS, JS) bypass the pipeline automatically.

Environment variables

VariableDescription
SEPTR_API_KEYYour project API key (required)
SEPTR_ENVEnvironment label sent with events (default production) — useful when several apps share one project
SEPTR_TELEMETRY_URLOverride the telemetry endpoint (Python SDK; e.g. a local backend)
SEPTR_HEARTBEAT_INTERVAL_MSHeartbeat cadence in ms (Python SDK; default 60000, 0 disables)
SEPTR_SILENCE_ENV_WARNINGSet to 1 to silence the missing-key warning
SEPTR_REMOTE_CONFIGSet to false to disable remote config polling

The project id is embedded in the API key (septr_live_<project-id>_<hash>) and read automatically — you never set it by hand.

Performance

Septr runs entirely in-process with no external calls on the hot path:

  • <5ms p50 overhead per request (measured across all engines)
  • Sub-2ms pattern matching per engine (in-memory regex)
  • Static asset bypass — 14 path prefixes + 13 file extensions skip the pipeline
  • Async telemetry — events buffered in-memory, flushed every 30s or at batch size 50
  • Zero memory growth under sustained load (verified at 1000 rate-limit checks in 0.4ms)

Troubleshooting

Missing API key warning

If you see a warning about SEPTR_API_KEY, make sure the environment variable is set before starting your app. In development:

SEPTR_API_KEY=septr_live_... node app.js

To suppress the warning in environments where the key is injected at runtime:

SEPTR_SILENCE_ENV_WARNING=1

Engine not detecting

All engines are enabled by default. If you disabled one for testing, re-enable it and restart your app. Check your config:

createSeptr({
  apiKey: process.env.SEPTR_API_KEY,
  // make sure these are all true:
  secrets: true,
  bola: true,
  rateLimit: true,
  inputSanitize: true,
  ssrf: true,
  promptInjection: true,
})

Telemetry not reaching dashboard

Make sure:

  • The API key is correct and the project is active
  • Septr middleware is mounted before your routes
  • Your server has outbound access to the telemetry endpoint
  • Restart your app and wait ~30 seconds for the first telemetry flush

Source scanning

Run septr scan . in your project root to scan source files for secrets, SQLi/XSS payloads, and SSRF indicators. Findings are reported with file:line, and the exit code is 1 when findings meet --fail-on (default high) — useful for CI gates.

Excluding files

Test fixtures and generated files can contain intentional attack payloads. Exclusions are explicit and committed, never silent:

  • .septrignore — gitignore-style patterns at your project root. Committed to the repo so exclusions are auditable.
  • --exclude — repeatable CLI flag for one-off runs: septr scan . --exclude "src/__tests__/**"
# .septrignore
# test fixtures contain intentional attack payloads — not vulnerabilities
src/__tests__/
# generated bundles are rebuilt, not fixed
dist/

Test fixture payloads (__tests__/benchmark/**, *-payloads.*, fixtures/**) are skipped by default. Everything else is scanned — including tests — so real secrets in test files are still caught.

npx septr scan . --json emits machine-readable findings; --quiet suppresses the summary.

Multiple apps & monorepos

One process or twenty, each app sends its own telemetry. How you group them in the dashboard is up to you:

  • One project per app (recommended). Each app gets its own key, incidents, score, and alerts — a noisy or misconfigured service can't drag another app's score down.
  • One project for a portal, one per service behind it. If several services sit behind a single domain, register that URL on one project so URL scans cover the public surface, and give each service its own project for runtime telemetry.

If you intentionally share a key across services, set a distinct environment label per app so events can be told apart:

SEPTR_ENV=checkout-api     # sent with every event (default "production")

Don't export one key to child processes. If a launcher script starts several services, let each service read its own SEPTR_API_KEY — a shared export routes every service's telemetry to the same project, which is rarely what you want.

Staging or self-hosted backend: point any app at it with SEPTR_TELEMETRY_URL=https://your-backend/v1/events. The default is https://app.septr.dev/v1/events.