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
}))
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
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.
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | env SEPTR_API_KEY | Your project API key |
telemetry | boolean | true | Send detections to the dashboard (set false to disable) |
strictMode | boolean | false | Block requests instead of detecting |
secrets | boolean | true | Secret/PII detection + response scrubbing |
bola | boolean | true | BOLA/IDOR detection |
rateLimit | boolean | true | Per-route rate limiting |
inputSanitize | boolean | true | SQLi/XSS/NoSQLi sanitization |
ssrf | boolean | true | SSRF heuristics |
promptInjection | boolean | true | Prompt-injection shielding |
aiRateLimit | boolean | true | Rate limiting for AI endpoints |
tamper | boolean | true | Business-logic tamper detection |
missingAuth | boolean | true | Missing-auth detection |
stripFields | string[] | [] | Fields to strip from responses |
telemetryUrl | string | https://app.septr.dev/v1/events | Telemetry endpoint |
projectId | string | derived from key | Project id; auto-read from septr_live_* keys |
remoteConfig | boolean | true | Poll 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 type | Limit |
|---|---|
| General | 60 requests/min |
| Auth endpoints | 10 requests/min |
| AI endpoints | 5 requests/min |
Static assets (/static/, /_next/, images, CSS, JS) bypass the pipeline automatically.
Environment variables
| Variable | Description |
|---|---|
SEPTR_API_KEY | Your project API key (required) |
SEPTR_ENV | Environment label sent with events (default production) — useful when several apps share one project |
SEPTR_TELEMETRY_URL | Override the telemetry endpoint (Python SDK; e.g. a local backend) |
SEPTR_HEARTBEAT_INTERVAL_MS | Heartbeat cadence in ms (Python SDK; default 60000, 0 disables) |
SEPTR_SILENCE_ENV_WARNING | Set to 1 to silence the missing-key warning |
SEPTR_REMOTE_CONFIG | Set 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.
SEPTR_TELEMETRY_URL=https://your-backend/v1/events. The default is https://app.septr.dev/v1/events.