securenow 8.24.0 → 8.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NPM_README.md +693 -305
- package/README.md +76 -28
- package/SKILL-API.md +648 -525
- package/SKILL-CLI.md +293 -663
- package/app-config.js +19 -1
- package/cidr.js +139 -20
- package/cli/init.js +77 -15
- package/cli/utils.js +26 -14
- package/cli.js +7 -5
- package/console-instrumentation.js +6 -0
- package/firewall-cloud.js +81 -32
- package/firewall-iptables.js +123 -62
- package/firewall-only.js +2 -0
- package/firewall-tcp.js +19 -5
- package/firewall.js +21 -1
- package/framework-routes.js +222 -0
- package/log-format.js +2 -0
- package/log-redaction.js +135 -0
- package/mcp/catalog.js +14 -9
- package/next-route.js +61 -0
- package/nextjs-middleware.js +8 -4
- package/nextjs-wrapper.js +8 -4
- package/nextjs.d.ts +35 -67
- package/nextjs.js +29 -6
- package/package.json +5 -2
- package/register.d.ts +27 -34
- package/request-capture.js +11 -6
- package/resolve-ip.js +23 -5
- package/sessions.d.ts +27 -0
- package/sessions.js +71 -10
- package/tracing.d.ts +40 -121
- package/tracing.js +12 -4
package/SKILL-CLI.md
CHANGED
|
@@ -2,812 +2,442 @@
|
|
|
2
2
|
|
|
3
3
|
> **Node.js security:** Use a supported, patched runtime: Node.js 22.23.4+, 24.22.1+, or 26.12.1+ on its respective release line. Earlier patches are affected by [CVE-2026-111497](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases). Upgrading the SecureNow package does not patch Node.js; upgrade the runtime and restart every application process.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The `securenow` CLI runs SecureNow from the terminal: set up an app, see what is attacking it, investigate an address, block, rate-limit, challenge, revoke sessions, write and test detection rules, work the review queues, and run the MCP server for coding agents. It describes securenow 8.24.0; items marked **(8.25.0+)** need 8.25.0 or newer. Wiring the SDK into an app is covered by [SKILL-API.md](./SKILL-API.md).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- `npx securenow help` lists every command; `npx securenow help <command>` shows its subcommands and flags. Both work offline: check a flag there before using it.
|
|
8
|
+
- Most read commands take `--json` for machine-readable output and `--app <key>` / `--env <environment>` to pick the target.
|
|
9
|
+
- Write commands act on production apps within about 10 seconds. Ask the person first; `--yes` (or `--force`) only skips the prompt after they agreed.
|
|
10
|
+
- Never print `.securenow/*.json` files or full `snk_live_` keys.
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
# Install globally (recommended for CLI usage)
|
|
11
|
-
npm install -g securenow
|
|
12
|
-
|
|
13
|
-
# Or install per-project and use via npx
|
|
14
|
-
npm install securenow@latest
|
|
15
|
-
npx securenow <command>
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
**Full parity with the SDK:** every capability the `securenow` Node SDK exposes has a CLI counterpart — redaction, CIDR matching, log/span emission, firewall preload, config inspection. If you can do it in code, you can do it from the terminal.
|
|
12
|
+
## Before you start
|
|
19
13
|
|
|
20
|
-
|
|
14
|
+
### Install
|
|
21
15
|
|
|
22
16
|
```bash
|
|
23
|
-
npx securenow
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
npx -p securenow securenow-mcp
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
The MCP server reads admin/control-plane auth from `.securenow/admin.json` and SDK runtime app credentials from `.securenow/runtime.json`, with legacy `.securenow/credentials.json` still supported. Admin/global tools use admin auth; runtime-scoped read tools can use the runtime API key where its scopes allow it. Write tools require `confirm:true` plus a reason.
|
|
30
|
-
|
|
31
|
-
**For agents, prefer the hosted MCP** (`https://api.securenow.ai/mcp`, OAuth sign-in, no install and always the current tools). With the local stdio server, warm the package once so the first connection doesn't time out on the download (`npx -y securenow@latest --version`), and give the client a longer connect timeout (Claude Code: `MCP_TIMEOUT=120000`).
|
|
32
|
-
|
|
33
|
-
**Tool profiles** (stdio server): `securenow mcp --profile <name>` (or `SECURENOW_MCP_PROFILE=<name>`) serves only the tools one job needs, so the agent carries less context. Every profile keeps `securenow_auth_status`, `securenow_apps_list` and `securenow_apps_info`; calling a tool outside the profile returns an error naming the profile.
|
|
34
|
-
|
|
35
|
-
| Profile | Tools | What's in it |
|
|
36
|
-
|---|---|---|
|
|
37
|
-
| `all` (default) | 112 | everything |
|
|
38
|
-
| `investigator` | 58 | every read-only tool, plus forensics question/chat/confirm |
|
|
39
|
-
| `detection` | 47 | `securenow_alert_rule*` (draft, create, test, run, runs, explain, versions, exclusions, request promotion…), traces, logs, forensics, IP intelligence, notifications list/get |
|
|
40
|
-
| `responder` | 77 | notifications, human queue, alert reviews, blocklist, allowlist, trusted IPs, rate limits, challenges, automations, firewall, IP intelligence, plus rule get/runs/explain and traces/logs for context |
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
claude mcp add securenow-investigator -- npx -y securenow@latest mcp --profile investigator
|
|
44
|
-
codex mcp add securenow-detection -- npx securenow mcp --profile detection
|
|
17
|
+
npm install securenow@latest # in the project; run commands with npx securenow <command>
|
|
18
|
+
npm install -g securenow # or globally: securenow <command>
|
|
19
|
+
npx securenow version
|
|
45
20
|
```
|
|
46
21
|
|
|
47
22
|
### Authenticate
|
|
48
23
|
|
|
49
24
|
```bash
|
|
50
|
-
securenow login
|
|
51
|
-
securenow admin login
|
|
52
|
-
securenow app connect
|
|
53
|
-
securenow
|
|
54
|
-
securenow
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**Two-lane credentials (v8.0+):** admin/control-plane auth lives in `.securenow/admin.json`; SDK runtime app config and the runtime API key live in `.securenow/runtime.json`. `securenow login` can run both lanes for onboarding, but `securenow admin login` never replaces runtime app config and `securenow app connect` never replaces admin auth. Legacy combined `.securenow/credentials.json` files are still read.
|
|
58
|
-
|
|
59
|
-
**Zero-config runtime flow:** the browser step lets the user pick (or create) an app. The CLI stores the app's **key (UUID)** and **name** in `.securenow/runtime.json`. The SDK sends traces/logs to the default SecureNow ingestion gateway, which routes by app key, so no env vars or per-instance collector URLs are required for local dev or production.
|
|
60
|
-
|
|
61
|
-
**Default-on security (v8.0+):** after picking or creating the app, `securenow app connect` turns on that app's firewall toggle, mints a runtime API key with `traces:write + logs:write + firewall:read + blocklist:read + allowlist:read` scopes, and writes it into `.securenow/runtime.json`. Traces, logs, POST body capture, multipart metadata capture, and the firewall are enabled by default. No `SECURENOW_API_KEY` env var is needed. To add or rotate a key later without re-running app connect, use `securenow api-key create` or `securenow api-key set snk_live_...` (see [API Key Management](#api-key-management) below).
|
|
62
|
-
|
|
63
|
-
Runtime credentials resolve in order: project `.securenow/runtime.json` -> legacy project `.securenow/credentials.json` -> project named runtime credentials -> global `.securenow/runtime.json` -> legacy global credentials -> global named runtime credentials. Admin auth resolves from `admin.json` first, then legacy `credentials.json`. Runtime config is credentials-json based; environment-variable fallbacks are not supported.
|
|
64
|
-
|
|
65
|
-
The **runtime API key** should live in runtime credentials as `apiKey`; it authenticates telemetry ingestion and firewall sync.
|
|
66
|
-
|
|
67
|
-
For CI / Docker / production, use `securenow credentials runtime --env production` to generate a tokenless runtime file, then mount/copy it as `.securenow/credentials.json`. Since v7.7.2, mounting the generated `.securenow/credentials.production.json` filename directly also works when `credentials.json` is absent.
|
|
68
|
-
|
|
69
|
-
**Environment model:** use one SecureNow app key for local, preview, staging, and production. The credentials field `config.runtime.deploymentEnvironment` separates traces/logs/firewall/forensics by environment. CLI security commands default to `production`; pass `--env local`, `--env staging`, or `--env all` only when that scope is intentional.
|
|
70
|
-
|
|
71
|
-
### Integrate With Your App
|
|
72
|
-
|
|
73
|
-
The CLI can also instrument any Node.js app at launch — no code changes:
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
# Express, Fastify, NestJS, Koa, Hapi, raw Node.js
|
|
77
|
-
securenow run src/index.js
|
|
78
|
-
|
|
79
|
-
# Or via the Node preload flag
|
|
80
|
-
node -r securenow/register src/index.js
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
For Next.js, run the interactive scaffolding:
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
securenow login
|
|
87
|
-
securenow init
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
This auto-detects your framework, creates the necessary `instrumentation.ts` and `next.config.js` changes, and reuses the app, instance, and runtime API key written by login or `app connect` to `.securenow/runtime.json`.
|
|
91
|
-
|
|
92
|
-
### Install This Skill in Cursor
|
|
93
|
-
|
|
94
|
-
Save this file as `.cursor/skills/securenow-cli/SKILL.md` in your project. Your AI agent will auto-discover it whenever you ask about CLI commands, security investigations, or firewall management.
|
|
95
|
-
|
|
96
|
-
## Configuration
|
|
97
|
-
|
|
98
|
-
Config lives in `~/.securenow/` (global) and optionally `.securenow/` (per-project):
|
|
99
|
-
|
|
100
|
-
| File | Content |
|
|
101
|
-
|------|---------|
|
|
102
|
-
| `~/.securenow/config.json` | `apiUrl`, `appUrl`, `defaultApp`, `output` |
|
|
103
|
-
| `~/.securenow/admin.json` | `token`, `email`, `expiresAt` for global admin/control-plane CLI and MCP auth |
|
|
104
|
-
| `~/.securenow/runtime.json` | `apiKey`, `app`, `config` for global SDK runtime |
|
|
105
|
-
| `.securenow/admin.json` | `token`, `email`, `expiresAt` for project-local admin/control-plane CLI and MCP auth |
|
|
106
|
-
| `.securenow/runtime.json` | `apiKey`, `app`, `config`, `_securenow.explanations` for project-local SDK runtime |
|
|
107
|
-
| `.securenow/credentials.json` | Legacy combined credentials; still read for backward compatibility |
|
|
108
|
-
| `.securenow/credentials.<environment>.json` | Tokenless runtime credentials generated by `securenow credentials runtime --env <environment>`; read in a fixed order, not selected from env vars |
|
|
109
|
-
|
|
110
|
-
**Credential resolution order:** runtime config resolves from project `.securenow/runtime.json` -> legacy project `.securenow/credentials.json` -> project named runtime credentials in the fixed staging/production/preview/local/test/development/dev/prod order -> global `.securenow/runtime.json` -> legacy global credentials -> global named runtime credentials. Admin auth resolves from `admin.json` first, then legacy `credentials.json`. Environment-variable fallbacks are not supported.
|
|
111
|
-
|
|
112
|
-
**Runtime API key resolution (v8.0+):** project `.securenow/runtime.json` -> legacy project credentials -> project named runtime credentials in the fixed staging/production/preview/local/test/development/dev/prod order -> global runtime credentials -> legacy global credentials -> global named runtime credentials. Use `securenow app connect` for runtime setup or `securenow api-key set` to rotate a key without touching admin auth or env vars.
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
securenow config set apiUrl https://api.securenow.ai
|
|
116
|
-
securenow config set defaultApp my-app-key
|
|
117
|
-
securenow config get # show all
|
|
118
|
-
securenow config get defaultApp # show one
|
|
119
|
-
securenow config path # print file paths + active auth source
|
|
25
|
+
npx securenow login # browser: admin auth + the app's runtime config (run from the project root)
|
|
26
|
+
npx securenow admin login # admin/control-plane auth only (CLI and MCP) [--token <TOKEN>] [--global]
|
|
27
|
+
npx securenow app connect # runtime only: pick/create the app, mint the runtime API key [--global]
|
|
28
|
+
npx securenow whoami # both lanes
|
|
29
|
+
npx securenow logout # clears admin auth; the runtime config stays [--global]
|
|
120
30
|
```
|
|
121
31
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
## Global Flags
|
|
125
|
-
|
|
126
|
-
| Flag | Short | Effect |
|
|
127
|
-
|------|-------|--------|
|
|
128
|
-
| `--json` | `-j` | JSON output (pipe-friendly) |
|
|
129
|
-
| `--help` | | Show help for any command |
|
|
130
|
-
| `--verbose` | `-v` | Verbose output |
|
|
131
|
-
| `--force` | `-f` | Skip confirmations |
|
|
132
|
-
| `--yes` | `-y` | Auto-confirm prompts |
|
|
133
|
-
|
|
134
|
-
SecureNow-specific environment overrides are not supported; use `.securenow/runtime.json`, `.securenow/admin.json`, or `securenow config set`.
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
## Command Reference
|
|
139
|
-
|
|
140
|
-
### Run — Instrument Any Node.js App
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
securenow run <script> # auto-detect CJS/ESM, inject OTel preload
|
|
144
|
-
securenow run --watch src/index.js # pass Node flags through
|
|
145
|
-
securenow run --inspect src/server.js --port 3000
|
|
146
|
-
securenow run --firewall-only app.js # preload firewall only (no tracing overhead)
|
|
147
|
-
securenow src/index.js # shorthand — auto-detected as "run"
|
|
148
|
-
```
|
|
32
|
+
Two lanes, two files: `.securenow/admin.json` (admin token for the CLI and MCP) and `.securenow/runtime.json` (app key, runtime API key `snk_live_...`, SDK config). `--global` writes to `~/.securenow/` instead of the project. Both files are secrets; the CLI adds them to `.gitignore` without ignoring the whole `.securenow/` folder. Never open an auth URL yourself: the CLI generates the callback.
|
|
149
33
|
|
|
150
|
-
|
|
34
|
+
### Pick the app and the environment
|
|
151
35
|
|
|
152
|
-
|
|
36
|
+
- One app key serves every environment. Traces, logs, firewall rules, forensics and alerts are scoped by `config.runtime.deploymentEnvironment` (`production`, `staging`, `preview`, `local`...).
|
|
37
|
+
- CLI security commands default to `production`. `npx securenow init` writes `local` for a development machine, so use `--env local` (or `--env all` where accepted) to see local traffic.
|
|
38
|
+
- `--app <key>` targets another app. `npx securenow apps default <key>` (or `npx securenow config set defaultApp <key>`) sets the default.
|
|
153
39
|
|
|
154
|
-
|
|
155
|
-
securenow login # friendly flow: admin auth + app runtime connection
|
|
156
|
-
securenow admin login # admin/control-plane CLI and MCP auth only
|
|
157
|
-
securenow admin login --token <JWT> # headless / CI admin auth
|
|
158
|
-
securenow app connect # app/runtime SDK connection only
|
|
159
|
-
securenow logout # clear admin auth; runtime app config remains
|
|
160
|
-
securenow logout --global # clear global admin auth only
|
|
161
|
-
securenow whoami # show admin auth and runtime app status separately
|
|
162
|
-
```
|
|
40
|
+
## Tasks
|
|
163
41
|
|
|
164
|
-
###
|
|
42
|
+
### Set up SecureNow in a project
|
|
165
43
|
|
|
166
44
|
```bash
|
|
167
|
-
|
|
168
|
-
securenow
|
|
169
|
-
securenow
|
|
170
|
-
securenow
|
|
171
|
-
securenow apps delete <id> [--force] # delete an app
|
|
172
|
-
securenow apps default <app-key> # set default app for all commands
|
|
173
|
-
securenow apps discover [appId] [--domain example.com] # discover subdomains, add as apps
|
|
174
|
-
securenow apps scan [--yes] # scan all app domains for new subdomains
|
|
45
|
+
npm install securenow@latest
|
|
46
|
+
npx securenow login
|
|
47
|
+
npx securenow init # [--env local] [--key snk_live_...] [--ts|--js] [--src|--root] [--force]
|
|
48
|
+
npx securenow doctor && npx securenow test-span
|
|
175
49
|
```
|
|
176
50
|
|
|
177
|
-
|
|
51
|
+
`init` detects the framework, fills `.securenow/runtime.json`, writes the Next.js instrumentation file and config, and prints the start-script change for plain Node. The full wiring per framework is in SKILL-API.md.
|
|
178
52
|
|
|
179
|
-
|
|
53
|
+
### Production credentials
|
|
180
54
|
|
|
181
55
|
```bash
|
|
182
|
-
securenow
|
|
183
|
-
securenow
|
|
184
|
-
securenow
|
|
185
|
-
securenow
|
|
186
|
-
securenow api-key show # print the masked current key + its source
|
|
187
|
-
securenow api-key clear # remove just the API key (keeps session/app)
|
|
188
|
-
securenow api-key clear --global # same, but from the global file
|
|
189
|
-
securenow credentials runtime --env production # write .securenow/credentials.production.json for production secret-file deploys
|
|
56
|
+
npx securenow credentials runtime --env production # writes .securenow/credentials.production.json
|
|
57
|
+
npx securenow credentials runtime --env production --format env # prints SECURENOW_CREDENTIALS=<base64>
|
|
58
|
+
npx securenow credentials runtime --env staging --out deploy/securenow.json
|
|
59
|
+
npx securenow credentials runtime --env production --stdout # JSON to stdout
|
|
190
60
|
```
|
|
191
61
|
|
|
192
|
-
The
|
|
62
|
+
The file carries the app key, the runtime API key and the SDK config, never the admin token. Mount it as `<app-root>/.securenow/credentials.json`, or store the `--format env` line as a secret environment variable (Vercel, Railway, Render, Heroku, Fly, Kubernetes). Both contain the runtime API key.
|
|
193
63
|
|
|
194
|
-
|
|
64
|
+
Runtime key only:
|
|
195
65
|
|
|
196
66
|
```bash
|
|
197
|
-
securenow
|
|
67
|
+
npx securenow api-key create --name "CLI runtime" # mint and save a key for the current app [--app <key-or-id>] [--global]
|
|
68
|
+
npx securenow api-key set snk_live_... # save a key you already have [--global]
|
|
69
|
+
npx securenow api-key show # masked key and its source
|
|
70
|
+
npx securenow api-key clear # remove the key only [--global]
|
|
198
71
|
```
|
|
199
72
|
|
|
200
|
-
|
|
201
|
-
- **Credentials**: ensures `.securenow/runtime.json` exists with secure defaults and explanations
|
|
202
|
-
- **Next.js**: creates `instrumentation.ts/js` with `securenow/nextjs` + `securenow/nextjs-auto-capture`, and adds `serverExternalPackages: ['securenow']` plus `outputFileTracingIncludes` when the config can be patched safely
|
|
203
|
-
- **Existing Next.js files**: prints a Codex/Claude-ready merge prompt when instrumentation or config already exists or is too custom to safely patch
|
|
204
|
-
- **Nuxt**: tells you to add `securenow/nuxt` to modules
|
|
205
|
-
- **Node/Express/etc.**: suggests adding `-r securenow/register` to start script
|
|
206
|
-
- Reuses `.securenow/runtime.json` written by login/app connect; production should mount/copy the tokenless runtime file generated by `securenow credentials runtime --env production`
|
|
207
|
-
|
|
208
|
-
### Dashboard & Status
|
|
73
|
+
### Today's overview
|
|
209
74
|
|
|
210
75
|
```bash
|
|
211
|
-
securenow today
|
|
212
|
-
securenow
|
|
213
|
-
securenow
|
|
214
|
-
securenow
|
|
76
|
+
npx securenow today # what happened, what SecureNow did, what needs you [--since 24h|7d] [--attackers 8]
|
|
77
|
+
npx securenow status --env production # apps, protection, unread alerts [--app <key>] [--env local|production|all]
|
|
78
|
+
npx securenow analytics --app <key> # response-code analytics
|
|
79
|
+
npx securenow logs errors --since 1h # what is failing: errors grouped by message [--warn] [--limit 20]
|
|
215
80
|
```
|
|
216
81
|
|
|
217
|
-
`today` is the dashboard's
|
|
218
|
-
- whether each app is covered (data flowing, firewall on, detection monitoring or blocking);
|
|
219
|
-
- attack requests, attackers, what the firewall stopped and what got through;
|
|
220
|
-
- the decisions waiting for you, the top attackers, and what SecureNow did (the agent's actions, automatic blocks,
|
|
221
|
-
closed probes).
|
|
222
|
-
|
|
223
|
-
`attacker <ip>` explains one address:
|
|
224
|
-
- the verdict and score with the signals behind them, and its reputation;
|
|
225
|
-
- where it is blocked;
|
|
226
|
-
- its last 3 days of traffic against your apps' normal (error rate, share of traffic, scanner probes, attack
|
|
227
|
-
payloads answered 2xx);
|
|
228
|
-
- the detections it triggered and what happened to each, a timeline, and questions to paste into
|
|
229
|
-
`securenow forensics chat`.
|
|
230
|
-
|
|
231
|
-
MCP: `securenow_overview` and `securenow_attacker` (read).
|
|
232
|
-
|
|
233
|
-
---
|
|
82
|
+
`today` is the dashboard's Overview: whether each app is covered (data flowing, firewall on, detection monitoring or blocking), attack requests and attackers, what the firewall stopped and what got through, decisions waiting, top attackers, and what SecureNow did. MCP: `securenow_overview`.
|
|
234
83
|
|
|
235
|
-
###
|
|
84
|
+
### Investigate an IP
|
|
236
85
|
|
|
237
86
|
```bash
|
|
238
|
-
securenow
|
|
239
|
-
securenow
|
|
240
|
-
securenow traces
|
|
241
|
-
securenow traces
|
|
87
|
+
npx securenow attacker 203.0.113.9 # why it was flagged: verdict, signals, traffic vs normal, detections, timeline
|
|
88
|
+
npx securenow ip 203.0.113.9 # geo, ASN, reputation, verdict
|
|
89
|
+
npx securenow ip traces 203.0.113.9 --env production # its requests
|
|
90
|
+
npx securenow traces show <traceId> --env production # one request: spans, headers, body (redacted)
|
|
91
|
+
npx securenow traces analyze <traceId> # AI analysis of a trace
|
|
92
|
+
npx securenow firewall hits --ip 203.0.113.9 --since 24h # what the firewall did to it
|
|
93
|
+
npx securenow agent verify 203.0.113.9 # the double-check the agent runs before acting (alert moment + 3 days)
|
|
94
|
+
npx securenow forensics chat --app <key> "what did 203.0.113.9 do in the last 24 hours?"
|
|
242
95
|
```
|
|
243
96
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
securenow logs [--app <key>] [--env production] [--limit N] [--minutes M] [--level error|warn|info]
|
|
248
|
-
securenow logs list --app my-app --env production --minutes 30 --level error
|
|
249
|
-
securenow logs trace <traceId> --env production # logs correlated to a specific trace
|
|
250
|
-
securenow logs errors --app my-app --since 6h [--warn] # what is failing: error lines grouped by message (ids/numbers normalized), counts, first/last seen, sample traces
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
For "what's broken right now?", start with `logs errors` (MCP `securenow_logs_errors`): one call returns the distinct failures, not hundreds of raw lines.
|
|
254
|
-
|
|
255
|
-
### Notifications
|
|
256
|
-
|
|
257
|
-
```bash
|
|
258
|
-
securenow notifications [--limit N] [--page P]
|
|
259
|
-
securenow notifications list --limit 20
|
|
260
|
-
securenow notifications read <id> # mark one as read
|
|
261
|
-
securenow notifications read-all # mark all as read
|
|
262
|
-
securenow notifications unread # unread count
|
|
263
|
-
```
|
|
97
|
+
`forensics chat` runs discovery queries, shows its SQL and ends each answer with findings; continue with `--conversation <id> "<follow-up>"`. `npx securenow forensics "<question>"` answers one question without memory. Trust the result rows over the summary. MCP: `securenow_attacker`, `securenow_ip_lookup`, `securenow_ip_traces`, `securenow_forensics_chat`.
|
|
264
98
|
|
|
265
|
-
###
|
|
99
|
+
### Triage notifications
|
|
266
100
|
|
|
267
|
-
SecureNow decides most things alone (instant blocks, automations, IP investigations,
|
|
268
|
-
rules). What it won't decide alone waits in two queues. Work **Alert Review** first: one rule fix
|
|
269
|
-
closes every run it caused and the Requires Human rows that came from the same noise.
|
|
101
|
+
SecureNow decides most things alone (instant blocks, automations, IP investigations, rules that pause themselves). What it won't decide waits in two queues; work **Alert Review** first, because one rule fix closes every run it caused.
|
|
270
102
|
|
|
271
103
|
| Queue | Question | Decisions | CLI |
|
|
272
104
|
|---|---|---|---|
|
|
273
|
-
| Alert Review | "Is this rule right?" A rule fired far too wide, or on
|
|
274
|
-
| Requires Human | "What do we do about this IP or plan?" An investigated IP with a verdict SecureNow won't act on alone, or a proposed plan | block, false positive, close without blocking, approve
|
|
275
|
-
|
|
276
|
-
### Alert Review — is this rule right?
|
|
105
|
+
| Alert Review | "Is this rule right?" A rule fired far too wide, or on your own infrastructure; it usually paused itself | tune the rule, keep it on, close or dismiss with a reason (never blocks or unblocks) | `securenow review` |
|
|
106
|
+
| Requires Human | "What do we do about this IP or plan?" An investigated IP with a verdict SecureNow won't act on alone, or a proposed plan | block, false positive, close without blocking, approve or reject a plan | `securenow human` |
|
|
277
107
|
|
|
278
108
|
```bash
|
|
279
|
-
securenow
|
|
280
|
-
securenow
|
|
281
|
-
securenow
|
|
282
|
-
securenow review show <notificationId> # one run
|
|
283
|
-
securenow review keep <notificationId> --reason "Correct detection" --yes # turn the rule back on, stop it auto-pausing, close the run
|
|
284
|
-
securenow review close <notificationId> --outcome rule_tuning --reason "..." --yes
|
|
285
|
-
securenow review dismiss <notificationId> --reason "Not worth acting on" --yes
|
|
286
|
-
securenow review group 1 --outcome rule_tuning --reason "Guard added in v4" --preview # what would close
|
|
287
|
-
securenow review group 1 --outcome rule_tuning --reason "Guard added in v4" --yes # close the whole group
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
Outcomes: `rule_tuning`, `false_positive`, `clean`, `deferred`, `new_alert_rule`, `rate_limited`,
|
|
291
|
-
`ambiguous`, `skipped`, `other`. Closing writes a decision report on the alert and changes no
|
|
292
|
-
enforcement. Tune the rule first (`securenow alerts rules change <id> "..."`), then close its group.
|
|
293
|
-
A mixed group (rows disagree on verdict or sender) needs `--allow-mixed` after reviewing every row.
|
|
294
|
-
|
|
295
|
-
MCP parity: `securenow_alert_review_runs_list`, `securenow_alert_review_run_get`,
|
|
296
|
-
`securenow_alert_review_run_keep_alive`, `securenow_alert_review_run_resolve`,
|
|
297
|
-
`securenow_alert_review_run_dismiss`, `securenow_alert_review_run_apply_group_decision`; prompt `work_alert_review`.
|
|
298
|
-
|
|
299
|
-
### Requires Human — what do we do about this IP or plan?
|
|
109
|
+
npx securenow notifications list --limit 20 # [--search <rule or IP>] [--severity critical|high|medium|low] [--page N]
|
|
110
|
+
npx securenow notifications unread
|
|
111
|
+
npx securenow notifications read <id> # or: read-all
|
|
300
112
|
|
|
301
|
-
|
|
113
|
+
npx securenow review # open runs grouped by root cause
|
|
114
|
+
npx securenow review show 1 # a group (row number or arc_ key) or one run (notification id)
|
|
115
|
+
npx securenow alerts rules change <rule-id> "ignore /healthz and raise the threshold to 20" # fix the rule first
|
|
116
|
+
npx securenow review group 1 --outcome rule_tuning --reason "Guard added" --preview
|
|
117
|
+
npx securenow review group 1 --outcome rule_tuning --reason "Guard added" --yes
|
|
118
|
+
npx securenow review keep <notificationId> --reason "Correct detection" --yes
|
|
119
|
+
npx securenow review dismiss <notificationId> --reason "Not worth acting on" --yes
|
|
302
120
|
|
|
303
|
-
|
|
304
|
-
securenow human
|
|
305
|
-
securenow human
|
|
306
|
-
securenow human
|
|
307
|
-
securenow human
|
|
308
|
-
securenow human
|
|
309
|
-
securenow human close 1 --outcome deferred --reason "Scanner, nothing reachable; not worth a block" --yes # leaves the queue, nothing blocked
|
|
310
|
-
securenow human action 1 --status rejected --yes --reason "Tuning guard is too broad"
|
|
311
|
-
securenow human prompt 1 # print a Codex/Claude MCP prompt for this row
|
|
312
|
-
securenow human work --limit 10 # list queue + print MCP runbook for deep queue work
|
|
121
|
+
npx securenow human # decisions waiting, most urgent first
|
|
122
|
+
npx securenow human show 1 # AI report, proofs, investigation steps, trace links
|
|
123
|
+
npx securenow human block 1 --reason "Confirmed SQL injection with 2xx answers" --yes
|
|
124
|
+
npx securenow human fp 1 --reason "Partner webhook, scoped to /api/hooks" --yes
|
|
125
|
+
npx securenow human close 1 --outcome deferred --reason "Scanner, nothing reachable" --yes
|
|
126
|
+
npx securenow human action 1 --status rejected --reason "Exclusion too broad" --yes
|
|
313
127
|
```
|
|
314
128
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
- `securenow_human_actions_list`
|
|
318
|
-
- `securenow_notifications_get`
|
|
319
|
-
- `securenow_human_action_report`
|
|
320
|
-
- `securenow_human_action_block`
|
|
321
|
-
- `securenow_human_action_false_positive`
|
|
322
|
-
- `securenow_human_action_close_no_write`
|
|
323
|
-
- `securenow_human_case_action_update`
|
|
324
|
-
- prompts: `investigate_human_action_row`, `work_human_actions`
|
|
325
|
-
|
|
326
|
-
`human report` only adds a note: the row stays. `human close` removes it without enforcement.
|
|
327
|
-
Approving a `tune_rule` or `create_exclusion` plan with `human action` records the decision and
|
|
328
|
-
changes nothing: change the rule first, then approve. Only `approve_block` blocks.
|
|
329
|
-
|
|
330
|
-
### The autonomous agent works the queues for you
|
|
129
|
+
Review outcomes: `rule_tuning`, `false_positive`, `clean`, `deferred`, `new_alert_rule`, `rate_limited`, `ambiguous`, `skipped`, `other`. A group whose rows disagree needs `--allow-mixed` after reviewing every row. `human report` only adds a note (the row stays); `human close` removes the row without enforcement; approving a `tune_rule` or `create_exclusion` plan with `human action` only records the decision (change the rule first); only `approve_block` blocks.
|
|
331
130
|
|
|
332
|
-
|
|
333
|
-
there is work, or on demand. Before any decision on an IP it runs the same double-check as
|
|
334
|
-
`agent verify`: what that IP did around the alert and over the last 3 days on every app, its
|
|
335
|
-
sign-ins, the trust lists and reputation. Its blocks only cover the alert's apps and expire. What it
|
|
336
|
-
may do is set per kind of action: `off`, `shadow` (record what it would do, change nothing),
|
|
337
|
-
`suggest` (leave the recommendation on the row for a person) or `act`.
|
|
131
|
+
Each notification carries an `ipInvestigations` array; act only on IPs whose own `status` is `open`:
|
|
338
132
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
securenow agent undo <id> --yes # unblock / reopen the row / roll the rule back
|
|
346
|
-
securenow agent runs # patrols: status, tool calls, cost, summary
|
|
347
|
-
securenow agent run # patrol now
|
|
348
|
-
securenow agent verify 203.0.113.9 # the double-check, for any IP
|
|
349
|
-
```
|
|
133
|
+
| Status | Meaning | Action |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| `open` | No determination yet | Investigate, then decide |
|
|
136
|
+
| `false_positive` | Dismissed by an exclusion, a verified bot or a trusted IP | Skip |
|
|
137
|
+
| `blocked` | Already on the blocklist | Skip |
|
|
138
|
+
| `clean` | Cleared as benign | Skip |
|
|
350
139
|
|
|
351
|
-
|
|
352
|
-
`case_action`. The API enforces all of it, whatever the model decides: the agent's token only reaches
|
|
353
|
-
the queue, verification and rule-tuning routes (never trust lists, the allowlist, unblocking,
|
|
354
|
-
automations or prod promotion), it can't block without a verification that allows it, it only edits
|
|
355
|
-
test-mode rules (prod rules get a proposal a person applies), and budgets cap each run and day. An
|
|
356
|
-
action type that people keep undoing drops back to shadow by itself.
|
|
140
|
+
Prefer `metadata.matchedSubdetectors` over guessing which part of a rule fired from the title.
|
|
357
141
|
|
|
358
|
-
|
|
142
|
+
**False-positive exclusions** keep known-safe traffic from alerting. Keep them as narrow as the evidence (app, rule, path, method, status, user agent, body shape):
|
|
359
143
|
|
|
360
144
|
```bash
|
|
361
|
-
|
|
362
|
-
|
|
145
|
+
npx securenow fp ai-fill --description "Stripe webhook POST to /api/stripe/webhook" --context '{"method":"POST","path":"/api/stripe/webhook"}'
|
|
146
|
+
npx securenow fp dry-run --conditions '[{"field":"path","operator":"starts_with","value":"/api/stripe/webhook"}]' # last 3 days
|
|
147
|
+
npx securenow fp create --conditions '[...]' --match-mode all --rule-scope any_rule --reason "Stripe webhook"
|
|
148
|
+
npx securenow fp create --path /api/events --method POST --path-safe standard --ua-safe standard --headers-safe standard --query-keys page,limit --reason "Event webhook"
|
|
149
|
+
npx securenow fp mark <notification-id> <ip> --rule-scope this_rule --reason "Known partner IP"
|
|
150
|
+
npx securenow alerts rules exclusions <rule-id> add --conditions '[...]' --reason "..." # one rule only
|
|
151
|
+
npx securenow fp list | show <id> | edit <id> --active false | delete <id> --yes
|
|
152
|
+
npx securenow fp test-body @request.json --conditions '[...]'
|
|
363
153
|
```
|
|
364
154
|
|
|
365
|
-
`
|
|
366
|
-
(`--max-alert-review-groups`, `--max-human-rows`). The API key's scopes are the hard limit: a
|
|
367
|
-
Read Only key cannot change anything; acting needs `notifications:write`, `alerts:write` and
|
|
368
|
-
`rate_limits:write`. Setup for Claude Code, Codex and Cursor: dashboard → Run With Your Agent.
|
|
155
|
+
Conditions are `{"field", "operator", "value"}`. Fields: `path`, `method`, `user_agent`, `status_code`, `request_body`, `request_headers`. Operators: `equals`, `not_equals`, `contains`, `not_contains`, `starts_with`, `ends_with`, `regex`, `in`, `not_in`, and structural checks (`path_safe_values`, `query_safe_values`, `query_has_only_keys`, `ua_safe_values`, `headers_safe_values`, `headers_has_only_keys`, `body_safe_values`, `body_is_format`, `body_has_only_fields`, `json_has_only_keys`, `json_safe_values`, `json_valid`, `json_max_depth`, `json_schema_match`); prefer the `*_safe_values` checks, which only excuse a request whose value is clean. Match modes: `all`, `any`. Scopes: `this_rule` (only through `fp mark`), `specific_rules` (with `--target-rules id1,id2`), `all_existing`, `any_rule` (the `fp create` default). Presets for `--*-safe`: `standard`, `strict`.
|
|
369
156
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
### Alerts
|
|
373
|
-
|
|
374
|
-
Before authoring any alert SQL, load the contract shipped by the installed package and compare
|
|
375
|
-
it with fields actually observed for the selected application:
|
|
376
|
-
|
|
377
|
-
```bash
|
|
378
|
-
securenow telemetry schema --json
|
|
379
|
-
securenow telemetry schema logs --json
|
|
380
|
-
securenow telemetry schema traces --json
|
|
381
|
-
securenow telemetry schema events --json
|
|
382
|
-
securenow telemetry fields --app <key> --env production --since 24h --source all --json
|
|
383
|
-
```
|
|
157
|
+
MCP: `securenow_alert_review_runs_list`, `securenow_alert_review_run_get`, `securenow_alert_review_run_keep_alive`, `securenow_alert_review_run_resolve`, `securenow_alert_review_run_dismiss`, `securenow_alert_review_run_apply_group_decision`, `securenow_human_actions_list`, `securenow_human_action_report`, `securenow_human_action_block`, `securenow_human_action_false_positive`, `securenow_human_action_close_no_write`, `securenow_human_case_action_update`; prompts `work_alert_review`, `work_human_actions`, `investigate_human_action_row`.
|
|
384
158
|
|
|
385
|
-
|
|
386
|
-
auth and telemetry access; it returns names, map scopes, data types, occurrence counts, and
|
|
387
|
-
custom event types, but never customer attribute values. Absence means "not observed in this
|
|
388
|
-
window," not "unsupported." Use only documented fields, and label a rule `READY` only when
|
|
389
|
-
its fields were observed and `alerts rules validate` succeeds. Otherwise label it
|
|
390
|
-
`NEEDS_INSTRUMENTATION`, `NEEDS_BASELINE`, or `NEEDS_CUSTOMER_DECISION` as appropriate.
|
|
159
|
+
### Block an IP
|
|
391
160
|
|
|
392
161
|
```bash
|
|
393
|
-
securenow
|
|
394
|
-
securenow
|
|
395
|
-
securenow
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
securenow
|
|
399
|
-
|
|
400
|
-
securenow alerts rules validate \ # dry-run a candidate query BEFORE creating any rule
|
|
401
|
-
--sql @rule.sql --app <key> # no rule id needed — auto-hosts on an existing (system) rule
|
|
402
|
-
securenow alerts rules create \ # create a custom detection rule from inline SQL
|
|
403
|
-
--name "Auth: magic-link brute force" \
|
|
404
|
-
--sql @rule.sql \ # SQL, @file, or - for stdin; scope apps with __USER_APP_KEYS__
|
|
405
|
-
--apps key1,key2 \ # or --applications-all
|
|
406
|
-
--severity high --schedule "*/15 * * * *" \
|
|
407
|
-
--nlp "single IP flooding /api/auth/signin or /api/auth/callback"
|
|
408
|
-
# create auto dry-runs + rolls back (deletes) on query failure; --no-validate to skip
|
|
409
|
-
securenow alerts rules show <id> # one rule; JSON: --json
|
|
410
|
-
securenow alerts rules set-sql <id> --sql @new.sql # replace a CUSTOM rule's SQL in place (alias: update <id> --sql)
|
|
411
|
-
securenow alerts rules delete <id> --yes # delete a custom rule (system rules: disable instead)
|
|
412
|
-
securenow alerts rules update <id> --applications-all # all current & future apps
|
|
413
|
-
securenow alerts rules update <id> --apps key1,key2 # explicit app keys only
|
|
414
|
-
securenow alerts rules test <id> --wait # dry-run an existing rule's query (default; --mode live inserts 6 synthetic attack requests)
|
|
415
|
-
securenow alerts rules change <id> "raise the threshold to 20" # rewrite a rule from English: checked, shown before/after, applied as a new version
|
|
416
|
-
securenow alerts rules runs <id> [--since 1h] # what each run saw and why it did or didn't notify (+ next scheduled run)
|
|
417
|
-
securenow alerts rules run <id> # run a periodic rule now and print the run (--no-wait to just queue it)
|
|
418
|
-
securenow alerts rules why <id> --ip <ip> [--since 1h] # why the rule did or didn't alert on one address: verdict + findings
|
|
419
|
-
securenow alerts rules quality <id> # was the rule right to fire? 14-day precision, alerts labeled wrong/unclear and why, what detection learning changed
|
|
420
|
-
securenow alerts rules dry-run-query <id> --sql @candidate.sql --app <key> --wait # candidate test against a specific host rule
|
|
421
|
-
securenow alerts rules tune-query <id> --sql @candidate.sql --reason "Preserve exploit detector, remove benign broad match" --apply-globally --yes
|
|
422
|
-
securenow alerts rules exclusions <id> list # embedded rule exclusions
|
|
423
|
-
securenow alerts channels # list alert channels (Slack, email, etc.)
|
|
424
|
-
securenow alerts history [--limit N] # past triggered alerts
|
|
162
|
+
npx securenow blocklist add 203.0.113.42 --env production --duration 24h --reason "credential stuffing"
|
|
163
|
+
npx securenow blocklist add 203.0.113.0/24 --route /admin --mode prefix --method ALL --reason "admin probing"
|
|
164
|
+
npx securenow firewall test-ip 203.0.113.42 --path /admin --method GET --env production # would it be blocked?
|
|
165
|
+
npx securenow blocklist list --env production # [--status active|removed] [--search 203.0.] [--approval-status pending]
|
|
166
|
+
npx securenow blocklist unblock <id> --reason "false alarm after review" # stops enforcement, keeps the history
|
|
167
|
+
npx securenow blocklist approve <pending-id> --yes # or: reject <pending-id> (records a scoped no-block decision)
|
|
168
|
+
npx securenow blocklist stats
|
|
425
169
|
```
|
|
426
170
|
|
|
427
|
-
|
|
428
|
-
(dry-run before anything exists) → `create …` (which itself dry-runs and auto-rolls-back on
|
|
429
|
-
failure) → if you later need to fix it, `set-sql <id> --sql @rule.sql` (custom rules) or
|
|
430
|
-
`delete <id>`. Detection `.sql` files may start with `--`/`/* */` comments. Custom-rule SQL is
|
|
431
|
-
editable; **system**-rule SQL changes go through `tune-query … --apply-globally`. Pick the
|
|
432
|
-
right tenant-scope column per table: logs (`signoz_logs.distributed_logs_v2`) use
|
|
433
|
-
`resources_string['service.name'] IN (__USER_APP_KEYS__)`, traces
|
|
434
|
-
(`signoz_traces.distributed_signoz_index_v3`) use `` `resource_string_service$$name` IN (__USER_APP_KEYS__) ``.
|
|
435
|
-
|
|
436
|
-
`alerts rules create` flags: `--name` (required); one of `--sql <sql|@file|->` or `--query-mapping-id <id>`; one of `--apps k1,k2` or `--applications-all`; optional `--description`, `--nlp` (plain-English intent), `--category`, `--severity critical|high|medium|low`, `--schedule <cron>` (default `*/15 * * * *`), `--throttle-minutes N` / `--no-throttle`, `--execution-mode scheduled|instant|hybrid`, `--channel id1,id2` (defaults to your in-app SecureNow channel). Detection SQL must scope app keys via the `__USER_APP_KEYS__` placeholder and select an `ip` column for per-IP aggregation/remediation: create and set-sql refuse SQL with no ip column (it would never notify) unless `--allow-no-ip`. A new periodic rule runs once right away. Requires `alerts:write`.
|
|
437
|
-
|
|
438
|
-
**Throttle = one alert per rule AND address** (8.17): an address alerted on within the window (default 15 min) is left out of the next runs' notifications, and other addresses still alert. Alert storms keep one alert per rule per window.
|
|
439
|
-
|
|
440
|
-
**When a rule stays quiet,** don't guess: `alerts rules runs <id>` shows every run's outcome — `notified`, `no_rows`, `throttled`, `suppressed_blocked` (already blocked, often by another rule's instant block), `suppressed_trusted`, `no_ip` (rows without an ip column), `storm`, `auto_resolved` (dismissed by an exclusion, trusted IP or verified bot), `skipped`, `error` — and which addresses were left out and why. `alerts rules why <id> --ip <ip>` ends in a verdict such as "Detected at 15:06:31 but not notified: 203.0.113.50 was already blocked by instant rule X". `--yes` on `from-text` refuses to create a rule whose check matches your data right now (it would alert at once, usually a bad baseline); review the rows, then `--yes --force` if they are a real attack.
|
|
441
|
-
|
|
442
|
-
MCP parity for quiet rules: `securenow_alert_rule_runs` (run history), `securenow_alert_rule_run_now` (write, confirm) and `securenow_alert_rule_explain` (`ip`, `since`: verdict + findings).
|
|
443
|
-
|
|
444
|
-
**Agents don't promote rules; they ask.** When a test-mode rule has proved itself, an agent runs `securenow alerts rules request-promotion <id> --reason "..." --evidence "..."` (MCP `securenow_alert_rule_request_promotion`). A person sees it on the rules page or with `securenow human promotions` and runs `securenow human approve-promotion <request-id> --yes` (the rule goes to prod, recorded as a rule version naming the approver) or `deny-promotion <request-id> --reason "..."`. API keys and MCP tokens can ask but not decide.
|
|
445
|
-
|
|
446
|
-
MCP parity for noisy alert-rule reviews:
|
|
447
|
-
|
|
448
|
-
- `securenow_alert_rule_get`
|
|
449
|
-
- `securenow_alert_rule_candidate_test` dry-runs a full candidate SQL query without saving it.
|
|
450
|
-
- `securenow_alert_rule_test_result` polls the dry-run.
|
|
451
|
-
- `securenow_alert_rule_query_update` updates the shared public query mapping behind a system rule for all customer copies. It is admin-only, requires `confirm:true`, `applyGlobally:true`, `reason`, and SQL that keeps `__USER_APP_KEYS__` tenant scoping.
|
|
452
|
-
- `securenow_alert_rule_instant_update` patches Instant rule conditions/config with stale-write guards. Fetch the rule first, pass `expectedRuleVersion` plus `expectedCurrentInstantHash`, use operations such as `remove_condition` / `add_condition` / `update_condition`, and set `applyGlobally:true` for system rules. The API runs seeded before/after checks and returns benign samples removed plus attack samples still matching. If global tuning is denied, it returns a structured admin handoff with the exact patch and missing permission.
|
|
453
|
-
- `securenow_alert_rule_exclusion_add` remains the last-resort customer-specific path; it supports restrictive conditions plus `matchMode` and should not be used to hide a generic system-rule bug.
|
|
454
|
-
|
|
455
|
-
For system-rule tuning, dry-run the candidate SQL first for scheduled rules, or use `dryRun:true` on `securenow_alert_rule_instant_update` for Instant rules. Save only when the guard preserves attack detection. Good guards add exact exploit tokens, dangerous schemes, matched subdetectors, sensitive path/status evidence, malicious user agents, or repeat thresholds; bad guards simply suppress a noisy path.
|
|
171
|
+
`--route` (aliases `--path`, `--pattern`) with `--mode prefix|exact|regex` and `--method` makes a scoped block; without them the block is global. `blocklist remove` is an alias of `unblock`. Running apps enforce it within about 10 seconds. In the app (layer 1), ranges are IPv4 CIDRs and IPv6 is matched by exact address.
|
|
456
172
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
### IP Intelligence
|
|
460
|
-
|
|
461
|
-
```bash
|
|
462
|
-
securenow ip <ip-address> # lookup (geo, ASN, threat score, reputation)
|
|
463
|
-
securenow ip lookup <ip-address> # same as above
|
|
464
|
-
securenow ip traces <ip-address> --env production # traces originating from this IP
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
### Forensics — Natural Language Security Queries
|
|
173
|
+
**Allowlist** is deny-by-default: once any active entry exists for an app and environment, only listed IPs get through. Use it only to lock an app to known IPs, with the person's approval. **Trusted IPs** are the safe way to mark known infrastructure (monitors, office VPN, your servers): alerts on them are suppressed and nobody is restricted.
|
|
468
174
|
|
|
469
175
|
```bash
|
|
470
|
-
securenow
|
|
471
|
-
securenow
|
|
472
|
-
securenow
|
|
473
|
-
securenow
|
|
474
|
-
securenow forensics chat --conversation <id> "what else did those IPs do?" # follow up: the chat remembers the earlier answers
|
|
475
|
-
securenow forensics conversations # list conversations (dashboard, CLI and agent ones)
|
|
476
|
-
securenow forensics conversations <id> # show one: questions, SQL, findings, rows
|
|
477
|
-
securenow forensics library # view saved/template queries
|
|
176
|
+
npx securenow allowlist add 198.51.100.7 --app <key> --env production --label "Office" --reason "Admin app locked to office"
|
|
177
|
+
npx securenow allowlist list | remove <id> | stats
|
|
178
|
+
npx securenow trusted add 198.51.100.20 --label "Uptime monitor" # [--app <key>] [--env <env>]
|
|
179
|
+
npx securenow trusted list | remove <id>
|
|
478
180
|
```
|
|
479
181
|
|
|
480
|
-
|
|
481
|
-
show. A follow-up sees the earlier questions, their findings, and the IPs and trace IDs in their results. MCP:
|
|
482
|
-
`securenow_forensics_chat` (pass `conversationId` to continue), `securenow_forensics_conversations_list`,
|
|
483
|
-
`securenow_forensics_conversation_get`. `securenow forensics "<q>"` and `securenow_forensics_query` answer one question
|
|
484
|
-
with no memory.
|
|
182
|
+
Default automations block by risk score (95+ for 7 days, 90–94 for 72 hours, 85–89 for 24 hours): `npx securenow automation list`, `automation defaults --yes`, `automation show <id>`, `automation dry-run <id>`, `automation execute <id> --yes`, `automation create|update|delete`.
|
|
485
183
|
|
|
486
|
-
|
|
184
|
+
MCP: `securenow_blocklist_add`, `securenow_blocklist_unblock`, `securenow_firewall_test_ip`, `securenow_allowlist_*`, `securenow_trusted_*`.
|
|
487
185
|
|
|
488
|
-
###
|
|
186
|
+
### Rate-limit a route
|
|
489
187
|
|
|
490
188
|
```bash
|
|
491
|
-
securenow
|
|
492
|
-
securenow
|
|
493
|
-
securenow
|
|
189
|
+
npx securenow ratelimit add --route /api/login --method POST --limit 5 --window 1m --env production --reason "login brute force"
|
|
190
|
+
npx securenow ratelimit add --route /api/ --limit 100 --window 1m --header x-api-key # per API key value
|
|
191
|
+
npx securenow ratelimit add --route /app --limit 300 --window 1m --cookie session # per session cookie value
|
|
192
|
+
npx securenow ratelimit add --route /api/export --limit 50 --window 1h --key-by global # one bucket for everyone
|
|
193
|
+
npx securenow ratelimit add 203.0.113.42 --limit 30 --window 1m --duration 24h # one IP or CIDR
|
|
194
|
+
npx securenow ratelimit parse "5 per minute per IP on POST /api/login for 2h" # draft only
|
|
195
|
+
npx securenow ratelimit from-text "5 per minute per IP on POST /api/login for 2h" --yes # create
|
|
196
|
+
npx securenow ratelimit test 203.0.113.42 --path /api/login --method POST --env production
|
|
197
|
+
npx securenow ratelimit list | show <id> | enable <id> | disable <id> | remove <id> --reason "..."
|
|
494
198
|
```
|
|
495
199
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
### Starter Protection — Rules Every App Gets
|
|
200
|
+
`--mode exact|prefix|regex` (default `prefix`), `--method` (default `ALL`), `--window 30s|1m|1h`, `--duration 24h|7d` (expiry), `--key-by ip|global|header|cookie` (`--header <name>` or `--cookie <name>` imply it). Header and cookie values are hashed; requests without them count per IP. Over the limit the app answers 429 with `Retry-After`. Rules are per environment and default to `production`; use `--env local` to try one on a local app. Counters live in each process unless the app sets `config.firewall.rateLimitStore` to a Redis URL. `rate-limit` is an alias of `ratelimit`. MCP: `securenow_rate_limit_parse`, `securenow_rate_limit_create_from_text`, `securenow_rate_limit_create`, `securenow_rate_limit_test`.
|
|
499
201
|
|
|
500
|
-
|
|
202
|
+
### Challenge bots
|
|
501
203
|
|
|
502
204
|
```bash
|
|
503
|
-
securenow
|
|
504
|
-
securenow
|
|
505
|
-
securenow
|
|
506
|
-
securenow
|
|
507
|
-
securenow
|
|
508
|
-
securenow protect disable --app <key> # off; stays off until someone turns it on
|
|
509
|
-
securenow protect learn --app <key> # detection learning now (it also runs hourly): label alerts, measure precision, learn safe exclusions
|
|
510
|
-
securenow protect status --rules # adds each rule's 14-day precision (right / right + wrong)
|
|
205
|
+
npx securenow challenge add --route /login --clearance 30m --env production --reason "credential stuffing wave"
|
|
206
|
+
npx securenow challenge add 203.0.113.0/24 --route /signup --difficulty 16 --escalate-to-block --fail-threshold 10 --block-ttl-hours 24
|
|
207
|
+
npx securenow challenge test 203.0.113.9 --path /login --method GET --env production
|
|
208
|
+
npx securenow challenge list | show <id> | enable <id> | disable <id> | remove <id> --reason "..."
|
|
209
|
+
npx securenow firewall hits --action captcha_challenged --since 1h
|
|
511
210
|
```
|
|
512
211
|
|
|
513
|
-
|
|
212
|
+
Browsers get an invisible proof of work (`--difficulty` in leading zero bits, 4–28, default 14: about a second or less) and a pass for `--clearance` (default 30m). Clients that don't accept HTML get a 403 JSON `challenge_required`, so don't challenge API routes used by non-browser clients. MCP: `securenow_challenge_create`, `securenow_challenge_list`, `securenow_challenge_update`, `securenow_challenge_remove`.
|
|
514
213
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
### Blocklist — Block Malicious IPs
|
|
214
|
+
### Revoke a stolen session
|
|
518
215
|
|
|
519
216
|
```bash
|
|
520
|
-
securenow
|
|
521
|
-
securenow
|
|
522
|
-
securenow
|
|
523
|
-
securenow
|
|
524
|
-
securenow blocklist unblock <id> --reason "False alarm after review"
|
|
525
|
-
securenow blocklist remove <id> # compatibility alias for unblock
|
|
526
|
-
securenow blocklist list --status removed # audit retained unblocks
|
|
527
|
-
securenow blocklist stats # block counts, top reasons
|
|
217
|
+
npx securenow revoke session <session-id> --reason "impossible travel" --duration 24h --app <key> # [--env <env>]
|
|
218
|
+
npx securenow revoke user <user-id> --reason "account takeover" # every session of that user; default expiry 7d
|
|
219
|
+
npx securenow revoke list # [--type session|user] [--status active|restored]
|
|
220
|
+
npx securenow revoke restore <revocation-id> --reason "verified with the user"
|
|
528
221
|
```
|
|
529
222
|
|
|
530
|
-
|
|
531
|
-
sets `pathPattern`, `--mode`/`--path-mode` chooses `prefix`, `exact`, or
|
|
532
|
-
`regex`, and `--method` limits enforcement to one HTTP method or `ALL`.
|
|
533
|
-
|
|
534
|
-
Unblock stops firewall enforcement but preserves the block report, history, and
|
|
535
|
-
unblock audit fields. Reblocking the same IP later creates a fresh active block
|
|
536
|
-
without erasing the previous investigation trail.
|
|
223
|
+
The app enforces it within 30 seconds, through one of: `"sessions": { "guard": true }` in its runtime config **(8.25.0+)**, `sessions.guard()` middleware, or `sessions.check(req)` **(8.25.0+)** (SKILL-API.md section 5.10). The session id is the SHA-256 of the Bearer token or session cookie, as it appears in `session.id` on traces and `session.seen` events; the user id is the JWT `sub` or what the app reports. There is no MCP tool for revocation: use this command.
|
|
537
224
|
|
|
538
|
-
|
|
539
|
-
work:
|
|
540
|
-
|
|
541
|
-
- `securenow_blocklist_unblock`
|
|
542
|
-
- `securenow_blocklist_remove` (compatibility alias for unblock)
|
|
543
|
-
- `securenow_blocklist_pending_list`
|
|
544
|
-
- `securenow_blocklist_pending_approve`
|
|
545
|
-
- `securenow_blocklist_pending_reject`
|
|
546
|
-
- `securenow_blocklist_pending_bulk_approve`
|
|
547
|
-
- `securenow_blocklist_pending_bulk_reject`
|
|
548
|
-
- prompt: `cleanup_legacy_pending_blocks`
|
|
549
|
-
|
|
550
|
-
### Rate Limits - Soft Remediation
|
|
225
|
+
### Create an alert rule from English and test it
|
|
551
226
|
|
|
552
227
|
```bash
|
|
553
|
-
securenow
|
|
554
|
-
securenow
|
|
555
|
-
securenow
|
|
556
|
-
securenow
|
|
557
|
-
securenow
|
|
228
|
+
npx securenow alerts rules from-text "one IP failing 10 sign-ins in 5 minutes" --app <key> --draft-only # see the checked draft
|
|
229
|
+
npx securenow alerts rules from-text "one IP failing 10 sign-ins in 5 minutes" --app <key> # create it (asks)
|
|
230
|
+
npx securenow alerts rules test <rule-id> --wait # dry run on real data (default)
|
|
231
|
+
npx securenow alerts rules test <rule-id> --mode live --wait # inserts 6 synthetic attack requests first
|
|
232
|
+
npx securenow alerts rules run <rule-id> # run a periodic rule now [--no-wait]
|
|
233
|
+
npx securenow alerts rules runs <rule-id> --since 1h # each run: notified, no_rows, throttled, suppressed_blocked, ...
|
|
234
|
+
npx securenow alerts rules why <rule-id> --ip 203.0.113.50 --since 2h
|
|
235
|
+
npx securenow alerts rules change <rule-id> "raise the threshold to 20" # rewrite from English as a new version
|
|
236
|
+
npx securenow alerts rules quality <rule-id> # 14-day precision, wrong alerts and why
|
|
237
|
+
npx securenow alerts rules promote <rule-id> --yes # a person: test → prod (demote: back to test)
|
|
238
|
+
npx securenow alerts rules request-promotion <rule-id> --reason "..." --evidence @evidence.md # what an agent does instead
|
|
558
239
|
```
|
|
559
240
|
|
|
560
|
-
MCP
|
|
241
|
+
`from-text` picks an instant rule (each request, as it arrives) or a periodic one (SQL on a schedule); force it with `--instant` or `--periodic`, and set `--name`, `--severity`, `--env` (default: every environment). New rules start in **test mode**: they alert, and no instant block, automation or agent acts on them. With `--yes`, `from-text` refuses a rule whose check matches your data right now (it would alert at once, usually a bad baseline); `--yes --force` creates it anyway when the rows are a real attack. A person approves promotion requests with `npx securenow human promotions` and `human approve-promotion <request-id> --yes` (or `deny-promotion <request-id> --reason "..."`); API keys and MCP tokens can ask but not decide.
|
|
561
242
|
|
|
562
|
-
|
|
563
|
-
- `securenow_rate_limit_create_from_text`
|
|
243
|
+
When a rule stays quiet, `alerts rules runs` names the outcome of every run (`notified`, `no_rows`, `throttled`, `suppressed_blocked`, `suppressed_trusted`, `no_ip`, `storm`, `auto_resolved`, `skipped`, `error`) and `alerts rules why` ends in a verdict such as "Detected at 15:06:31 but not notified: 203.0.113.50 was already blocked". The throttle sends one alert per rule and address per window (default 15 minutes).
|
|
564
244
|
|
|
565
|
-
|
|
245
|
+
**SQL rules.** Read the contract first and check the fields the app really sends:
|
|
566
246
|
|
|
567
247
|
```bash
|
|
568
|
-
securenow
|
|
569
|
-
securenow
|
|
570
|
-
securenow
|
|
571
|
-
securenow
|
|
572
|
-
|
|
248
|
+
npx securenow telemetry schema --json # offline: tables, timestamps, tenant scope, event mapping, templates [logs|traces|events]
|
|
249
|
+
npx securenow telemetry fields --app <key> --env production --since 24h --json # names, types, counts, event types (never values)
|
|
250
|
+
npx securenow alerts rules validate --sql @rule.sql --app <key> # dry-run before creating anything
|
|
251
|
+
npx securenow alerts rules create --name "Auth: magic-link brute force" --sql @rule.sql --apps <key> \
|
|
252
|
+
--severity high --schedule "*/15 * * * *" --nlp "single IP flooding /api/auth/signin"
|
|
253
|
+
npx securenow alerts rules create --name "Secrets probe" --apps <key> \
|
|
254
|
+
--conditions '[{"field":"path","operator":"contains","value":"/.env"}]' # an instant rule, no SQL
|
|
255
|
+
npx securenow alerts rules set-sql <rule-id> --sql @rule.sql # replace a custom rule's SQL
|
|
256
|
+
npx securenow alerts rules delete <rule-id> --yes
|
|
573
257
|
```
|
|
574
258
|
|
|
575
|
-
|
|
576
|
-
uses the canonical `riskScore`: 95-100 blocks for 7 days, 90-94 blocks for 72h,
|
|
577
|
-
85-89 blocks for 24h, and scores below 85 stay in investigation/review unless
|
|
578
|
-
the customer adds a stricter custom rule. Raw SecureNow IPDB confidence remains
|
|
579
|
-
supporting evidence, not the primary automation score.
|
|
259
|
+
Scope app keys with `__USER_APP_KEYS__` (logs: `resources_string['service.name'] IN (__USER_APP_KEYS__)`; traces: `` `resource_string_service$$name` IN (__USER_APP_KEYS__) ``) and return an `ip` column (SQL without one is refused unless `--allow-no-ip`: it would never notify). `create` dry-runs the query and deletes the rule again if it fails (`--no-validate` skips that); a new periodic rule runs once right away. Label a rule `READY` only when its fields were observed and `validate` succeeded, otherwise `NEEDS_INSTRUMENTATION` (the app must send a `track()` event), `NEEDS_BASELINE` or `NEEDS_CUSTOMER_DECISION`. Details: `node_modules/securenow/TELEMETRY-SQL.md`. System rules are tuned with `alerts rules tune-query <id> --sql @candidate.sql --reason "..." --apply-globally --yes` (admin), after `alerts rules dry-run-query <id> --sql @candidate.sql --app <key> --wait`.
|
|
580
260
|
|
|
581
|
-
|
|
261
|
+
MCP: `securenow_alert_rule_draft`, `securenow_alert_rule_create`, `securenow_alert_rule_test`, `securenow_alert_rule_runs`, `securenow_alert_rule_run_now`, `securenow_alert_rule_explain`, `securenow_alert_rule_request_promotion`, `securenow_alert_rule_candidate_test`, `securenow_alert_rule_instant_update`, `securenow_alert_rule_quality`.
|
|
582
262
|
|
|
583
|
-
|
|
584
|
-
allowlist entry exists for an app/environment, only listed IPs can reach it and
|
|
585
|
-
all other IPs are blocked. Do not use allowlist to mark an IP trusted, suppress
|
|
586
|
-
false positives, or clean up investigations. Use `securenow trusted add` for
|
|
587
|
-
known-safe monitors, office/VPN traffic, or trusted bypass cases.
|
|
263
|
+
### Starter protection
|
|
588
264
|
|
|
589
265
|
```bash
|
|
590
|
-
securenow
|
|
591
|
-
securenow
|
|
592
|
-
securenow
|
|
593
|
-
securenow
|
|
594
|
-
securenow
|
|
266
|
+
npx securenow protect # the current app: mode, rules, alerts, ready to block? [--all] [--rules] [--json]
|
|
267
|
+
npx securenow protect enable --app <key> # monitor mode: rules alert, nothing is blocked
|
|
268
|
+
npx securenow protect block --app <key> # a signed-in person only: block-ready rules block for 6 hours
|
|
269
|
+
npx securenow protect monitor --app <key> # back to alerts only
|
|
270
|
+
npx securenow protect disable --app <key> # off until someone turns it on [--yes]
|
|
271
|
+
npx securenow protect learn --app <key> # detection learning now (it also runs hourly)
|
|
595
272
|
```
|
|
596
273
|
|
|
597
|
-
|
|
274
|
+
Every app gets about 20 starter rules in monitor mode when it is created or first sends traffic. `protect block` is refused for API keys, MCP connectors and the agent, and while more than 20% of the app's traffic arrives through a proxy the SDK doesn't trust (fix with `config.networking.trustedProxies`). Detection learning labels each alert (right, wrong, unclear), keeps each rule's 14-day precision per app and adds a safe exclusion only when it excuses the wrong alerts and none of the right ones. MCP: `securenow_protection_status`, `securenow_protection_learn`.
|
|
598
275
|
|
|
599
|
-
|
|
600
|
-
and do not enable deny-by-default allowlist mode.
|
|
276
|
+
### Let the autonomous agent work the queues
|
|
601
277
|
|
|
602
278
|
```bash
|
|
603
|
-
securenow
|
|
604
|
-
securenow
|
|
605
|
-
securenow
|
|
606
|
-
securenow
|
|
279
|
+
npx securenow agent # status: on/off, mode per action, what it did, agreement with people
|
|
280
|
+
npx securenow agent on # or: off (also revokes a run in progress)
|
|
281
|
+
npx securenow agent mode all shadow # record what it would do, change nothing
|
|
282
|
+
npx securenow agent mode block_ip act --yes # then hand over one kind of action at a time
|
|
283
|
+
npx securenow agent activity --mode applied # every decision with its evidence [--action block_ip] [--page N]
|
|
284
|
+
npx securenow agent undo <id> --yes # unblock, reopen the row, or roll the rule back
|
|
285
|
+
npx securenow agent runs # patrols: status, tool calls, cost, summary
|
|
286
|
+
npx securenow agent run # patrol now
|
|
607
287
|
```
|
|
608
288
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
### False Positive Management
|
|
289
|
+
Actions: `close_row`, `false_positive`, `block_ip`, `review_close`, `keep_rule`, `rule_change`, `case_action` (or `all`); modes: `off`, `shadow`, `suggest`, `act`. The API enforces the limits whatever the model decides: the agent's token reaches only the queue, verification and rule-tuning routes, it can't block without a verification that allows it, and an action type that people keep undoing drops back to shadow by itself.
|
|
612
290
|
|
|
613
|
-
|
|
291
|
+
Your own harness instead: `npx securenow agent prompts` lists the runbooks; `npx securenow agent prompt patrol` prints one (`patrol`, `alert-review`, `human-queue`; `--confirm-writes` for the variant that may act, `--search`, `--limit`, `--max-alert-review-groups`, `--max-human-rows`):
|
|
614
292
|
|
|
615
293
|
```bash
|
|
616
|
-
securenow
|
|
617
|
-
securenow fp list
|
|
618
|
-
securenow fp show <id> # rule details
|
|
619
|
-
securenow fp delete <id> [--yes]
|
|
620
|
-
|
|
621
|
-
# Create exclusion rules
|
|
622
|
-
securenow fp create \
|
|
623
|
-
--conditions '[{"field":"path","operator":"starts_with","value":"/api/health"}]' \
|
|
624
|
-
--match-mode all \
|
|
625
|
-
--rule-scope any_rule \
|
|
626
|
-
--reason "Health check endpoint"
|
|
627
|
-
|
|
628
|
-
# Shorthand safe-value presets
|
|
629
|
-
securenow fp create \
|
|
630
|
-
--path /api/events \
|
|
631
|
-
--method POST \
|
|
632
|
-
--path-safe standard \
|
|
633
|
-
--ua-safe standard \
|
|
634
|
-
--headers-safe standard \
|
|
635
|
-
--query-keys page,limit \
|
|
636
|
-
--headers-keys host,content-type \
|
|
637
|
-
--reason "Event webhook"
|
|
638
|
-
|
|
639
|
-
# Edit an existing rule
|
|
640
|
-
securenow fp edit <id> [--active true|false] [--conditions '[...]']
|
|
641
|
-
|
|
642
|
-
# Test conditions against a request body
|
|
643
|
-
securenow fp test-body '{"user":"admin"}' --conditions '[{"field":"request_body","operator":"contains","value":"\"user\":\"admin\""}]'
|
|
644
|
-
securenow fp test-body @request.json --conditions '[...]'
|
|
645
|
-
|
|
646
|
-
# Dry-run conditions against the last 3 days of live traces
|
|
647
|
-
securenow fp dry-run --conditions '[{"field":"path","operator":"starts_with","value":"/api/webhook"}]'
|
|
648
|
-
|
|
649
|
-
# AI-generate exclusion conditions from a description
|
|
650
|
-
securenow fp ai-fill --description "Stripe webhook POST to /api/stripe/webhook" \
|
|
651
|
-
--context '{"method":"POST","path":"/api/stripe/webhook"}'
|
|
652
|
-
|
|
653
|
-
# Mark an IP as false positive on a specific notification
|
|
654
|
-
securenow fp mark <notification-id> <ip> \
|
|
655
|
-
[--conditions '[...]'] \
|
|
656
|
-
[--reason "Known partner IP"] \
|
|
657
|
-
[--rule-scope this_rule|specific_rules|all_existing|any_rule] \
|
|
658
|
-
[--target-rules id1,id2]
|
|
294
|
+
claude -p "$(npx -y securenow@latest agent prompt patrol --search my-app --confirm-writes)" --allowedTools "mcp__securenow"
|
|
659
295
|
```
|
|
660
296
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
**Condition fields:** `path`, `method`, `user_agent`, `status_code`, `request_body`, `request_headers`.
|
|
664
|
-
|
|
665
|
-
**Operators:** `equals`, `not_equals`, `contains`, `not_contains`, `starts_with`, `ends_with`, `regex`, `in`, `not_in`, plus structural checks — `path_safe_values`, `query_safe_values`, `query_has_only_keys`, `ua_safe_values`, `headers_safe_values`, `headers_has_only_keys`, `body_safe_values`, `body_is_format`, `body_has_only_fields`, `json_has_only_keys`, `json_safe_values`, `json_valid`, `json_max_depth`, `json_schema_match`. Prefer the `*_safe_values` checks over `contains`: they only exclude a request whose value is clean.
|
|
666
|
-
|
|
667
|
-
**Match modes:** `all` (AND logic), `any` (OR logic).
|
|
668
|
-
|
|
669
|
-
**Rule scopes:** `this_rule` (single alert rule — only via `fp mark`; for a rule-only exclusion without a notification use `securenow alerts rules exclusions <rule-id> add --conditions '[...]'`), `specific_rules` (comma-separated IDs via `--target-rules`), `all_existing` (all current rules), `any_rule` (all current and future rules; the `fp create` default).
|
|
670
|
-
|
|
671
|
-
**Safe-value presets:** `standard` or `strict`. These auto-generate conditions that whitelist common safe patterns for paths, query strings, user-agents, and headers.
|
|
672
|
-
|
|
673
|
-
---
|
|
674
|
-
|
|
675
|
-
### Instances
|
|
297
|
+
### Set up MCP
|
|
676
298
|
|
|
677
299
|
```bash
|
|
678
|
-
securenow
|
|
679
|
-
securenow
|
|
680
|
-
securenow
|
|
300
|
+
npx securenow login # the local server uses this auth
|
|
301
|
+
claude mcp add securenow -- npx securenow mcp # Claude Code
|
|
302
|
+
codex mcp add securenow -- npx securenow mcp # Codex
|
|
303
|
+
claude mcp add --transport http securenow https://api.securenow.ai/mcp # hosted server, OAuth sign-in
|
|
681
304
|
```
|
|
682
305
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
### Telemetry — Emit Logs and Spans From the Shell
|
|
686
|
-
|
|
687
|
-
Mirrors the SDK's `getLogger()` and tracing APIs. Useful for cron jobs, shell scripts, and CI pipelines that need to push events into SecureNow without booting the full OTel SDK.
|
|
688
|
-
|
|
689
|
-
```bash
|
|
690
|
-
# Send a structured log record to the OTLP collector
|
|
691
|
-
securenow log send "Deployment completed" --level info --attrs version=1.2.3,service=api
|
|
692
|
-
securenow log send "Backup failed" --level error --attrs host=db-01
|
|
306
|
+
Cursor, `.cursor/mcp.json`:
|
|
693
307
|
|
|
694
|
-
|
|
695
|
-
securenow
|
|
696
|
-
securenow test-span "ci.smoke-test" # custom span name
|
|
308
|
+
```json
|
|
309
|
+
{ "mcpServers": { "securenow": { "command": "npx", "args": ["securenow", "mcp"] } } }
|
|
697
310
|
```
|
|
698
311
|
|
|
699
|
-
|
|
312
|
+
- The local stdio server is `npx securenow mcp` (also the `securenow-mcp` bin). Admin tools use `.securenow/admin.json`; app-scoped reads can use `.securenow/runtime.json`. Warm the package once (`npx -y securenow@latest --version`) so the first connection doesn't time out on the download, and give the client a longer connect timeout (Claude Code: `MCP_TIMEOUT=120000`).
|
|
313
|
+
- The hosted server `https://api.securenow.ai/mcp` needs no install and always has the current tools: OAuth sign-in with a SecureNow account (or `Authorization: Bearer <API key>`). The SecureNow plugin for Claude Code and Codex bundles it with skills (`/plugin marketplace add securenow-ai/claude-plugin`, then `/plugin install securenow@securenow`).
|
|
314
|
+
- Read tools are annotated read-only; every write tool refuses to run without `confirm: true` and a non-empty `reason`. Resources: the installed SKILL-API.md, SKILL-CLI.md and NPM_README.md, the project config, the tool catalog. Prompts: `secure_project_setup`, `verify_firewall_default_on`, `investigate_ip`, `investigate_human_action_row`, `work_human_actions`, `work_alert_review`, `soc_patrol`, `agent_patrol`, `cleanup_legacy_pending_blocks`, `configure_default_automation`.
|
|
315
|
+
- Profiles serve only the tools one job needs (`npx securenow mcp --profile <name>` or `SECURENOW_MCP_PROFILE=<name>`). Every profile keeps `securenow_auth_status`, `securenow_apps_list` and `securenow_apps_info`; a tool outside the profile returns an error naming it.
|
|
700
316
|
|
|
701
|
-
|
|
317
|
+
| Profile | Tools | Contents |
|
|
318
|
+
|---|---|---|
|
|
319
|
+
| `all` (default) | 125 | everything |
|
|
320
|
+
| `investigator` | 65 | every read-only tool, plus forensics question/chat/confirm |
|
|
321
|
+
| `detection` | 53 | alert rules (draft, create, test, run, runs, explain, versions, exclusions, request promotion...), traces, logs, forensics, IP intelligence, notifications |
|
|
322
|
+
| `responder` | 82 | notifications, both queues, blocklist, allowlist, trusted IPs, rate limits, challenges, automations, firewall, IP intelligence, plus rule get/runs/explain and traces/logs |
|
|
702
323
|
|
|
703
|
-
|
|
324
|
+
```bash
|
|
325
|
+
claude mcp add securenow-investigator -- npx -y securenow@latest mcp --profile investigator
|
|
326
|
+
```
|
|
704
327
|
|
|
705
|
-
|
|
328
|
+
### Emit an event, a log or a span from a script
|
|
706
329
|
|
|
707
330
|
```bash
|
|
708
|
-
|
|
709
|
-
securenow
|
|
710
|
-
securenow
|
|
711
|
-
|
|
712
|
-
# CIDR operations — match an IP against a list, or parse a range
|
|
713
|
-
securenow cidr match 10.0.0.5 10.0.0.0/24,192.168.0.0/16
|
|
714
|
-
securenow cidr parse 10.0.0.0/24 # network, broadcast, mask, size
|
|
715
|
-
|
|
716
|
-
# Show resolved config (service name, endpoints, credentials, firewall layers)
|
|
717
|
-
securenow env # human-readable
|
|
718
|
-
securenow env --json # pipe to jq
|
|
719
|
-
|
|
720
|
-
# End-to-end diagnostic: probe OTLP + API endpoints, check config
|
|
721
|
-
securenow doctor # exits 0 if healthy, 1 otherwise
|
|
722
|
-
securenow doctor --json
|
|
331
|
+
npx securenow event send auth.login.failure --user u_123 --ip 203.0.113.10 --attrs reason=bad_password,method=password
|
|
332
|
+
npx securenow event send auth.otp.send.result --session s_1 --level warn --attrs status=failed --env staging
|
|
333
|
+
npx securenow log send "Backup failed" --level error --attrs host=db-01 # --level trace|debug|info|warn|error|fatal
|
|
334
|
+
npx securenow test-span ci.smoke-test --env production
|
|
723
335
|
```
|
|
724
336
|
|
|
725
|
-
|
|
337
|
+
`event send` posts one custom event to the `/v1/events` ingest with the runtime credentials (`--user`, `--session`, `--ip`, `--user-agent`, `--level`, `--attrs k=v,k=v`, `--env`): the same event `track()` sends from Node, for cron jobs, CI or non-JS services. `log send` and `test-span` exit non-zero on HTTP errors, so CI can catch failures.
|
|
726
338
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
## Workflow Examples for Agentic AI
|
|
730
|
-
|
|
731
|
-
### Investigate a Security Alert
|
|
339
|
+
### Diagnose a setup
|
|
732
340
|
|
|
733
341
|
```bash
|
|
734
|
-
securenow
|
|
735
|
-
#
|
|
736
|
-
securenow
|
|
737
|
-
securenow
|
|
738
|
-
securenow
|
|
739
|
-
securenow
|
|
740
|
-
#
|
|
741
|
-
securenow blocklist add <attacker-ip> --reason "Automated: SQL injection detected"
|
|
342
|
+
npx securenow env # resolved service name, environment, endpoints, firewall (no secrets) [--json]
|
|
343
|
+
npx securenow doctor # probes traces, logs, API and firewall sync; exit 1 on failure [--json]
|
|
344
|
+
npx securenow test-span # "Span accepted (HTTP 200)"
|
|
345
|
+
npx securenow firewall status --env production # the app's firewall state, layers, blocklist
|
|
346
|
+
npx securenow firewall apps # every app with its firewall on/off per environment
|
|
347
|
+
npx securenow firewall enable --app <key> --env production # or: disable
|
|
348
|
+
npx securenow config path # config and credential files in use
|
|
742
349
|
```
|
|
743
350
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
Each notification contains an `ipInvestigations` array. **Every IP has its own `status` field** that you MUST check before taking action or raising flags. Do not rely only on top-level notification fields — always cross-reference each IP's individual investigation status.
|
|
747
|
-
|
|
748
|
-
| Status | Meaning | Action |
|
|
749
|
-
|--------|---------|--------|
|
|
750
|
-
| `open` | Still needs review — no determination yet | Investigate: run `securenow ip <ip>`, check traces, decide to block or dismiss |
|
|
751
|
-
| `false_positive` | Trusted/dismissed by exclusion rule, verified bot, or trusted IP list | **Skip** — greyed out in UI, no action needed |
|
|
752
|
-
| `blocked` | Already on the user's blocklist | **Skip** — already handled |
|
|
753
|
-
| `clean` | Pipeline analyzed and cleared as benign | **Skip** — verified safe |
|
|
754
|
-
|
|
755
|
-
**Critical workflow rule:** When investigating notifications, iterate `ipInvestigations[]` and **only flag or act on IPs with `status: "open"`**. IPs marked `false_positive`, `blocked`, or `clean` have already been triaged — do not re-flag them.
|
|
756
|
-
|
|
757
|
-
### Triage and Suppress a False Positive
|
|
351
|
+
### Threat-modeling prompts
|
|
758
352
|
|
|
759
353
|
```bash
|
|
760
|
-
securenow
|
|
761
|
-
|
|
762
|
-
securenow
|
|
763
|
-
# Review the suggested conditions, then create the rule
|
|
764
|
-
securenow fp create --conditions '<ai-suggested-conditions>' --rule-scope any_rule --reason "Stripe webhook"
|
|
765
|
-
# Or directly mark the notification's IP as FP
|
|
766
|
-
securenow fp mark <notification-id> <ip> --rule-scope this_rule --reason "Known Stripe IP"
|
|
354
|
+
npx securenow threat-model --list
|
|
355
|
+
npx securenow threat-model authentication --out threat-prompt.md # then: "Follow threat-prompt.md"
|
|
356
|
+
npx securenow threat-model authentication | claude -p
|
|
767
357
|
```
|
|
768
358
|
|
|
769
|
-
|
|
359
|
+
Categories include `authentication`, `authorization`, `injection`, `api-security`, `rate-limits-and-abuse`, `webhooks`, `ai-llm-features` and more (`--list`).
|
|
770
360
|
|
|
771
|
-
|
|
772
|
-
securenow apps create my-new-app --hosts api.example.com,app.example.com
|
|
773
|
-
securenow apps default my-new-app
|
|
774
|
-
securenow login
|
|
775
|
-
securenow init
|
|
776
|
-
securenow run src/index.js
|
|
777
|
-
securenow status --json
|
|
778
|
-
```
|
|
779
|
-
|
|
780
|
-
### Security Posture Check
|
|
361
|
+
### Utilities
|
|
781
362
|
|
|
782
363
|
```bash
|
|
783
|
-
securenow
|
|
784
|
-
securenow
|
|
785
|
-
securenow
|
|
786
|
-
securenow forensics "summarize all attacks in the last 7 days"
|
|
364
|
+
npx securenow redact '{"user":"alice","password":"s3cret","otpCode":"123456","status_code":200}' # [--fields f1,f2] or @file.json
|
|
365
|
+
npx securenow cidr match 10.0.0.5 10.0.0.0/8,192.168.1.0/24 # exit 0 = match, 2 = no match
|
|
366
|
+
npx securenow cidr parse 10.0.0.0/24 # network, broadcast, mask, size
|
|
787
367
|
```
|
|
788
368
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
```bash
|
|
792
|
-
securenow apps discover --domain example.com
|
|
793
|
-
securenow apps scan --yes
|
|
794
|
-
```
|
|
369
|
+
`redact` uses the same rules as SDK capture (field names, OTP names matched exactly so `status_code` stays, secret-shaped values).
|
|
795
370
|
|
|
796
|
-
|
|
371
|
+
## Command reference
|
|
797
372
|
|
|
798
|
-
|
|
373
|
+
`securenow help <command>` is authoritative. Subcommand flags not listed by `help` are shown in its usage lines below.
|
|
799
374
|
|
|
800
|
-
|
|
375
|
+
| Command | Subcommands | Key flags |
|
|
376
|
+
|---|---|---|
|
|
377
|
+
| `run` | `run [node-flags] [--firewall-only] <script> [args]`; `securenow <script.js>` is a shorthand | `--firewall-only`, Node flags pass through (`--watch`, `--inspect`) |
|
|
378
|
+
| `login` | | `--token`, `--global` |
|
|
379
|
+
| `logout` | | `--global` |
|
|
380
|
+
| `whoami` | | |
|
|
381
|
+
| `admin` | `login` (default), `logout` | `--token`, `--global` |
|
|
382
|
+
| `app` | `connect` (default) | `--global` |
|
|
383
|
+
| `credentials` | `runtime` (default) | `--env` (default `production`), `--out`, `--stdout`, `--format env` |
|
|
384
|
+
| `api-key` | `create`, `set <key>`, `clear`, `show` (default) | `create`: `--name`, `--app <key-or-id>`, `--preset runtime_app`, `--global` |
|
|
385
|
+
| `init` | | `--env` (default `local`), `--key snk_live_...`, `--ts` (`--typescript`), `--js` (`--javascript`), `--src`/`--root` (Next.js file folder; default `src/` when `app/` or `pages/` is there), `--force` (replace the instrumentation file, keeping a `.bak`) |
|
|
386
|
+
| `apps` | `list` (default), `create <name>`, `info <id>`, `delete <id>`, `default <key>`, `discover [appId]`, `scan` | `create`: `--hosts h1,h2`, `--instance <id>`; `delete`: `--force`; `discover`: `--domain`; `scan`: `--yes` |
|
|
387
|
+
| `status` | | `--app`, `--env local\|production\|all` |
|
|
388
|
+
| `today` | | `--since 1h..7d` (default 24h), `--attackers <n>` (default 8), `--json` |
|
|
389
|
+
| `attacker` | `attacker <ip>` | `--json` |
|
|
390
|
+
| `traces` | `list` (default), `show <traceId>`, `analyze <traceId>` | `--app`, `--env`, `--limit`, `--start`, `--end` |
|
|
391
|
+
| `logs` | `list` (default), `trace <traceId>`, `errors` | `--app`, `--env`, `--since 30m\|6h\|2d`, `--minutes`, `--level trace\|debug\|info\|warn\|error\|fatal`, `--limit`, `--start`, `--end`; `errors`: `--warn` |
|
|
392
|
+
| `analytics` | | `--app` |
|
|
393
|
+
| `protect` | `status` (default), `enable`, `disable`, `block`, `monitor`, `learn` | `--app`, `--all`, `--rules`, `--yes` |
|
|
394
|
+
| `agent` | `status` (default), `on`, `off`, `mode <action> <mode>`, `activity`, `undo <id>`, `runs`, `run`, `verify <ip>`, `prompt <name>`, `prompts` | `--action`, `--mode`, `--page`, `--notification`, `--yes`, `--confirm-writes`, `--limit`, `--search`, `--max-alert-review-groups`, `--max-human-rows` |
|
|
395
|
+
| `human` | `list` (default), `show`, `block`, `fp`, `close`, `report`, `action`, `prompt`, `work`, `promotions`, `approve-promotion`, `deny-promotion` | `--reason`, `--outcome`, `--summary`, `--evidence`, `--yes`, `--search`, `--limit`, `--page`, `--status`, `--note`, `--conditions`, `--rule-scope`, `--create-exclusion`, `--missing-proof` |
|
|
396
|
+
| `review` | `list` (default), `show`, `keep`, `close`, `dismiss`, `group` | `--outcome`, `--reason`, `--summary`, `--preview`, `--allow-mixed`, `--search`, `--yes` |
|
|
397
|
+
| `notifications` | `list` (default), `read <id>`, `read-all`, `unread` | `list`: `--limit`, `--page`, `--search`, `--severity` |
|
|
398
|
+
| `alerts` | `rules` (default), `channels`, `history` | `history`: `--limit` |
|
|
399
|
+
| `alerts rules` | `list` (default), `from-text`, `change`, `create`, `show`, `update`, `duplicate`, `promote`, `demote`, `set-sql`, `validate`, `dry-run-query`, `tune-query`, `delete`, `test`, `run`, `runs`, `why`, `quality`, `exclusions <id> [list\|add\|delete]`, `versions`, `version`, `rollback`, `request-promotion` | `--app`, `--apps`, `--applications-all`, `--env`, `--instant`, `--periodic`, `--draft-only`, `--name`, `--sql`, `--conditions`, `--severity`, `--schedule`, `--throttle-minutes`, `--no-throttle`, `--channel`, `--allow-no-ip`, `--no-validate`, `--mode dry_run\|live` (test) / `test\|prod` (list, update), `--status`, `--wait`, `--ip`, `--since`, `--limit`, `--reason`, `--evidence`, `--apply-globally`, `--yes`, `--force` |
|
|
400
|
+
| `fp` | `list` (default), `show`, `create`, `edit`, `delete`, `test-body`, `dry-run`, `ai-fill`, `mark <notification-id> <ip>` | `--conditions`, `--match-mode`, `--rule-scope`, `--target-rules`, `--path`, `--method`, `--path-safe`, `--query-safe`, `--query-keys`, `--ua-safe`, `--headers-safe`, `--headers-keys`, `--reason`, `--description`, `--context`, `--active` |
|
|
401
|
+
| `ip` | `ip <address>` (lookup), `lookup`, `traces <ip>` | `traces`: `--app`, `--env` |
|
|
402
|
+
| `forensics` | `forensics "<question>"`, `query`, `chat`, `conversations [<id>]`, `library` | `--app`, `--env`, `chat`: `--conversation <id>`, `--yes` |
|
|
403
|
+
| `firewall` | `status` (default), `apps`, `enable`, `disable`, `test-ip <ip>`, `hits` | `--app`, `--env`; `test-ip`: `--path`, `--method`; `hits`: `--since`, `--action blocked\|rate_limited\|captcha_challenged`, `--source`, `--rule`, `--ip`, `--limit` |
|
|
404
|
+
| `automation` | `list` (default), `defaults`, `show`, `create`, `update`, `dry-run`, `execute`, `delete` | `--name`, `--conditions`, `--actions`, `--logic`, `--status`, `--body`, `--file`, `--app`, `--applications-all`, `--env`, `--environments-all`, `--limit`, `--sample-limit`, `--yes`; `defaults`: `--force-enable` |
|
|
405
|
+
| `ratelimit` (alias `rate-limit`) | `list` (default), `add [ip]`, `parse`, `from-text`, `show`, `test <ip>`, `enable`, `disable`, `remove` | `--route`/`--path`, `--mode`, `--method`, `--limit`, `--window`, `--duration`, `--key-by`, `--header`, `--cookie`, `--key-name`, `--app`, `--env`, `--reason`, `--text` |
|
|
406
|
+
| `challenge` | `list` (default), `add [ip]`, `show`, `test <ip>`, `enable`, `disable`, `remove` | `--route`/`--path`, `--mode`, `--method`, `--difficulty` (4–28, default 14), `--clearance` (default 30m), `--duration`, `--escalate-to-block`, `--fail-threshold` (10), `--block-ttl-hours` (24), `--app`, `--env`, `--reason` |
|
|
407
|
+
| `blocklist` | `list` (default), `add <ip>`, `unblock <id>`, `remove <id>`, `approve <id>`, `reject <id>`, `stats` | `--route`/`--path`/`--pattern`, `--mode`/`--path-mode`, `--method`, `--duration`, `--app`, `--env`, `--reason`, `--status`, `--approval-status`, `--search`, `--view`, `--page`, `--limit` |
|
|
408
|
+
| `revoke` | `list` (default), `session <id>`, `user <id>`, `restore <id>` | `--reason`, `--duration` (default 7d), `--app`, `--env`, `--type`, `--status` |
|
|
409
|
+
| `allowlist` | `list` (default), `add <ip>`, `remove <id>`, `stats` | `--app` (comma-separated), `--env`, `--label`, `--reason`, `--page`, `--limit` |
|
|
410
|
+
| `trusted` | `list` (default), `add <ip>`, `remove <id>` | `--app`, `--env`, `--label` |
|
|
411
|
+
| `telemetry` | `schema` (default) `[all\|logs\|traces\|events]`, `fields` | `--app`, `--env`, `--since` (max 30d), `--source`, `--limit` (1–500), `--json` |
|
|
412
|
+
| `log` | `send <message>` (default) | `--level`, `--attrs`, `--env` |
|
|
413
|
+
| `event` | `send <type>` (default) | `--user`, `--session`, `--ip`, `--user-agent`, `--level`, `--attrs`, `--env` |
|
|
414
|
+
| `test-span` | `test-span [<name>]` | `--env` |
|
|
415
|
+
| `threat-model` | `threat-model <category>` | `--list`, `--out` |
|
|
416
|
+
| `redact` | `redact '<json>'` or `@file` | `--fields` |
|
|
417
|
+
| `cidr` | `match <ip> <cidrs>`, `parse <cidr>` | |
|
|
418
|
+
| `doctor` | | `--json` |
|
|
419
|
+
| `env` | | `--json` |
|
|
420
|
+
| `mcp` | | `--profile all\|investigator\|detection\|responder` |
|
|
421
|
+
| `instances` | `list` (default), `test <id>` | |
|
|
422
|
+
| `config` | `get [key]`, `set <key> <value>`, `path` | keys: `apiUrl`, `appUrl`, `defaultApp` |
|
|
423
|
+
| `version` | | |
|
|
424
|
+
|
|
425
|
+
## Flags, environment and errors
|
|
801
426
|
|
|
802
|
-
|
|
427
|
+
| Flag | Short | Effect |
|
|
428
|
+
|---|---|---|
|
|
429
|
+
| `--json` | `-j` | JSON output for scripts and agents |
|
|
430
|
+
| `--help` | | Help for the command |
|
|
431
|
+
| `--yes` | `-y` | Confirm a write without the prompt |
|
|
432
|
+
| `--force` | `-f` | Same as `--yes` on most write commands |
|
|
803
433
|
|
|
804
|
-
|
|
805
|
-
|------------------|---------|----------|
|
|
806
|
-
| `Session expired` | Admin JWT expired | `securenow admin login` (or `admin login --global` for shared admin auth) |
|
|
807
|
-
| `Not logged in` | No admin token found | `securenow admin login`; runtime `.securenow/runtime.json` is unrelated |
|
|
808
|
-
| `Access denied (403)` | Insufficient permissions | Check the user's role in the account/organization |
|
|
809
|
-
| `HTTP 402` | The 14-day trial ended and the account has no active subscription (everything, including the firewall, is paused) | Subscribe in the dashboard: $99 per app per month, every feature included |
|
|
810
|
-
| `Cannot connect` | API unreachable | Check `securenow config get apiUrl` or network |
|
|
811
|
-
| `Unknown command` | Typo or unrecognized command | `securenow help` |
|
|
434
|
+
Environment variables the CLI reads: `NO_COLOR` (plain output), `SECURENOW_MCP_PROFILE` (MCP tool profile), `SECURENOW_CREDENTIALS` (runtime credentials, used by `env`, `doctor`, `test-span`, `log send`, `event send`). The admin token always comes from `admin.json` (`npx securenow admin login`).
|
|
812
435
|
|
|
813
|
-
|
|
436
|
+
| Error | Meaning | Recovery |
|
|
437
|
+
|---|---|---|
|
|
438
|
+
| `Session expired` | The admin token expired | `npx securenow admin login` |
|
|
439
|
+
| `Not logged in` | No admin token found | `npx securenow admin login` (the runtime file is a separate lane) |
|
|
440
|
+
| `Access denied (403)` | The user's role or the key's scopes don't allow it | Check the role in the organization or the API key's scopes |
|
|
441
|
+
| `HTTP 402` | The 14-day trial ended and the account has no subscription; everything, the firewall included, is paused | Subscribe in the dashboard ($99 per app per month, every feature) |
|
|
442
|
+
| `Cannot connect` | API unreachable | Network, or `npx securenow config get apiUrl` |
|
|
443
|
+
| `Unknown command` | Typo | `npx securenow help` |
|