#01A07 · A01 · API2
Authentication
Login, sessions, password reset, MFA, and account-takeover paths.
How to use this prompt
- 1Install SecureNow in your project (then optionally
npx securenow login):$ npm install securenow - 2Copy the prompt below and paste it into your AI coding agent (Claude Code, Cursor, Codex…) opened at the root of your project.
- 3It generates four files into
threat/01-authentication/— openauthentication-code-findings.html(the audit) andauthentication-detection-mitigation.html(the defenses) in your browser.
🔒Runs entirely in your environment — your codebase is never uploaded or shared. The generated HTML reports are self-contained and work offline.
The prompt
# Authentication Threat Model — Generator Prompt
A **copy-paste prompt** for customers. Paste the entire prompt below into an AI coding agent
(Claude Code, Cursor, Codex, …) opened at the root of **any project** that has the
`securenow` SDK installed (`node_modules/securenow`) and the CLI logged in. The agent will
analyze the codebase, build an exhaustive authentication threat model, ground every rule and
command in the **installed** SecureNow SDK, and emit a SecureNow-branded **two-track**
deliverable set: an operational **Detection & Mitigation** runbook (what to run in SecureNow,
with ready-to-copy rule + command blocks) and a **Code Findings & Recommendations** audit
(issues in the codebase + fixes), each in **Markdown + self-contained HTML** with offline copy
buttons.
Requirements on the customer machine: the project depends on `securenow` (so
`node_modules/securenow` exists — otherwise `npm i securenow`) and the CLI is authenticated
(`securenow login`; admin auth + app runtime connected). Everything else is discovered by the
agent.
---
<!-- ════════════════ COPY EVERYTHING BELOW THIS LINE ════════════════ -->
# Generate an Authentication Threat Model Report (SecureNow)
You are a senior application-security engineer. Produce an **exhaustive authentication
threat model for THIS codebase**, mapped to **SecureNow** detections and mitigations, with a
ready-to-run action plan. **Ground every alert rule and CLI command in the `securenow` SDK
that is actually installed in this repo** (`node_modules/securenow`) — never guess flags,
subcommands, event names, or SQL columns. Emit every detection as a **ready-to-copy** unit
(SQL → save to `rules/<name>.sql` → full `securenow alerts rules create …` → dry-run test).
You write **four** deliverables — **two tracks** — into `threat/01-authentication/` (create the
folder if needed):
1. `authentication-detection-mitigation.md` — the **operational runbook**: what to run in
SecureNow (detection rules to create, mitigation commands, testing, response runbooks).
2. `authentication-detection-mitigation.html` — the same runbook as a **self-contained** HTML
page (inline CSS + copy JS, no network requests) with a **Copy button on every command
block**, using the SecureNow branding skeleton given at the end of this prompt.
3. `authentication-code-findings.md` — the **code audit**: authentication issues found in the
codebase + recommended fixes (described, never applied).
4. `authentication-code-findings.html` — the same audit as a self-contained HTML page.
The two tracks **cross-link** each other: gap/instrumentation rows in the detection report link
to the relevant code finding, and each code finding links back to the detection row it backs.
Work in the phases below, in order. Never invent facts: if something is not in the codebase or
not returned by a CLI command, say "not found" — do not guess.
**Scope discipline for authentication messages.** This model owns every message whose purpose is
authentication or account recovery: OTP, magic link, email verification, password reset, MFA
challenge, and recovery notification. Audit both the **security property** and the **paid side
effect**. Do not defer SMS pumping, email/SMS bombing, voice-OTP toll fraud, provider-quota
exhaustion, or resend/fallback amplification merely because the messaging model also covers the
transport. Link `../11-messaging-notifications/` for the deeper provider, content, relay, and
deliverability audit, but keep the auth-flow threats and detections here.
SecureNow can see request traffic automatically and can correlate app-emitted events. It cannot
know that a provider accepted a send, which destination prefix was billed, the actual cost, or
whether an OTP was verified unless the app emits privacy-safe events at those decision points.
Every paid-flow row must therefore pair edge containment with app-owned per-target/per-account/
per-device quotas, a global spend or volume circuit breaker, idempotency, and provider-side fraud
controls. An IP-only limit is never sufficient for auth-message abuse.
---
## Phase 0 — Verify SecureNow tooling
Run and record (use `--json` where supported):
```bash
securenow doctor # connectivity must be healthy
securenow whoami # admin auth + runtime app
securenow status --json # app key(s), environment, firewall state
securenow alerts rules --json # detection rules that already exist
securenow automation --json # blocklist automations that already exist
securenow challenge list --json # CAPTCHA / proof-of-work challenge rules already configured
securenow env --json # resolved SDK config (service name, endpoints)
```
If the CLI is missing or not logged in, **stop** and tell the user to run
`npm i -g securenow && securenow login`, then re-run this prompt. Capture the **app key**
(UUID) — every rule and command in the report must use it. If multiple apps exist, ask the
user which app this codebase maps to before continuing.
---
## Phase 0.5 — Ground every rule & command in the INSTALLED SDK
Before writing any SQL or CLI, read the SecureNow SDK that is actually installed in this repo so
every alert rule and command is correct for THIS version — never guess flags, subcommands, event
names, or SQL columns:
```bash
cat node_modules/securenow/package.json # installed SDK version (record it in both reports)
ls node_modules/securenow # exported modules: events, sessions, register, run, …
ls node_modules/securenow/dist 2>/dev/null # built entrypoints / bundled CLI
npx securenow --help # top-level commands available in this version
npx securenow alerts rules --help # exact create flags: --name/--sql/--apps/--severity/--schedule/--nlp
npx securenow event --help # `event send` shape for synthetic tests
npx securenow ratelimit --help; npx securenow challenge --help
npx securenow blocklist --help; npx securenow automation --help; npx securenow trusted --help
```
If `node_modules/securenow` is absent, run `npm ls securenow`; if still missing, tell the user to
`npm i securenow` (or `npm i -g securenow`) and stop. EVERY command, flag, `track()` signature,
and SQL column you emit MUST be one the installed SDK/CLI actually exposes. Inspect whether
`track(type, props)` accepts an arbitrary string type (current SDKs do); if so, the canonical custom
event names defined by this prompt are allowed but must be labeled **proposed instrumentation**,
not falsely described as automatic SDK events. If the installed SDK validates a closed event-name
enum, use only that enum or annotate the required SDK change. If the installed
version lacks another capability this prompt references, emit the rule but annotate it
`# requires securenow >= <version>` instead of a broken command. Record the resolved version in
the appendix of BOTH reports.
In Phase 4 and Phase 5, treat `node_modules/securenow` + `--help` as the source of truth: the
`securenow/events` `track()` signatures, the `securenow alerts rules` SQL columns, and every
mitigation subcommand are discoverable there. Cross-check before emitting.
---
## Phase 1 — Discover the authentication surface (codebase analysis)
Search the codebase and document what is **actually implemented**. Cover at minimum:
- **Mechanisms** — password login, magic link, OTP/SMS, OAuth/OIDC providers, SAML/SSO,
WebAuthn/passkeys, API keys, mTLS, basic auth, dev/test backdoors.
- **Endpoints** — login, logout, signup, callback, token refresh, password reset/forgot,
email/phone change, MFA enroll/challenge, session polling. List the exact routes.
- **Session model** — JWT vs server-side sessions, signing algorithm and secret source,
lifetime, cookie flags (httpOnly/secure/SameSite/domain), revocation capability.
- **Credential storage** — hashing algorithm and parameters, salting, pepper.
- **MFA** — factors offered, where it can be skipped, recovery codes, remember-me.
- **Recovery flows** — reset-token generation, lifetime, single-use, host/URL construction.
- **Existing protections** — rate limiters (and whether in-memory or shared), lockout
policy, CAPTCHA, WAF/CDN in front; whether client IP/device identity is trustworthy; whether
counters are atomic and shared across every instance/region; and whether limits are keyed by
account/target as well as IP.
- **Authentication message & cost map** — for every OTP, magic-link, verification, reset, MFA,
and recovery send, record route + method, channel (email/SMS/voice/WhatsApp/push), provider,
whether the provider call happens before or after validation/rate limiting, who controls the
destination, destination country/prefix policy, unit/segment cost if configured, retries,
fallback channels, fan-out, and idempotency. Record every current budget: per IP, account,
target, device, ASN, destination prefix/country, tenant, and global daily spend/volume cap;
also record cool-down, provider fraud protection, and the emergency circuit breaker.
- **Identity binding & normalization** — email/phone canonicalization, duplicate-account rules,
verification-before-use, account linking, and whether a newly registered identifier can be
pre-hijacked then silently linked to an IdP account.
- **Security-change & attack-chain map** — enumerate password/reset completion, email/phone
change, factor enroll/remove/reset, recovery-code regeneration, support-assisted recovery,
session creation/revocation, OAuth grant/link, API-key creation, role/admin change, export,
payout, and other high-impact post-login actions. Record the durable user/account, session,
device, source IP/ASN, timestamp, and opaque correlation ID available at each step so chained
detections can be built.
- **Provider control plane & quality telemetry** — inventory messaging/identity-provider audit
logs, signed webhooks, polling/export APIs, delivery/fraud outcomes, spend/usage feeds, API-key
creation/rotation, sender/service/config changes, destination geo-policy changes, and sends made
directly in the provider rather than through this app. State which signals currently enter
SecureNow and which require a privacy-safe adapter/event.
- **Detection-pipeline health** — expected ratio of traced auth requests to auth events, expected
provider callbacks/outcomes, deployment instances emitting telemetry, exporter/queue errors,
rule status, notification-channel health, and the independent monitor/heartbeat (if any). Note
explicitly that a total SecureNow ingestion/exporter outage cannot reliably alert through the
same failed path.
- **Evasion & response safety** — alternate/versioned/mobile/GraphQL auth routes, encoding/case/
trailing-slash aliases, IPv4/IPv6 rotation, residential proxies, spoofable forwarding headers,
shared NAT/CGNAT, and whether an automated response could punish the victim account/recipient
or lock out legitimate recovery.
- **Detection governance** — owner, threshold source, baseline window, test/prod mode, notification
channel, runbook, reversible action, last validation date, and false-positive budget for every
existing auth rule.
- **Machine auth** — API key format/scopes/rotation, service-to-service trust, webhooks.
- **Secrets hygiene** — auth secrets in the repo, in client bundles, in logs.
- **SecureNow instrumentation already present** — `securenow/register` or `securenow run`,
`securenow/sessions` `guard()`/`capture()`, `securenow/events` `track()` calls, NextAuth
event wiring. This determines which detections work *today* vs *after instrumentation*.
Output of this phase = the **Surface & inventory** section of the **code-findings** report: a
component table (Login / Session / Storage / MFA / Recovery / Existing limits / Sensitive paths),
an **auth-message cost/control table** (one row per paid send path), plus a short paragraph naming
the real attack surface for this stack. The detection report's
"SDK & environment" section reuses the relevant subset (app key, env, existing instrumentation).
---
## Phase 2 — Enumerate threats (exhaustive catalog)
Evaluate **every** threat below against the discovered stack. Each item is either
**modeled** (gets a row in the threat matrix) or **explicitly N/A** (one line in an
"Out of scope" subsection with the reason — e.g. "password spraying: N/A, passwordless
app"). Never silently drop an item. Add stack-specific threats you discover that are not
listed — this catalog is the floor, not the ceiling.
**A. Credential attacks**
1. Single-IP brute force on login
2. Distributed / low-and-slow brute force (botnet, rotating IPs within an ASN)
3. Credential stuffing (breached pairs; one IP or ASN → many accounts)
4. Password spraying (one password → many accounts, lockout-evading)
5. Default / weak / seeded test credentials reachable in production
**B. Enumeration & reconnaissance**
6. Account enumeration via login/signup/reset response or timing oracle
7. Identifier harvesting at scale (one IP probing many emails/usernames)
8. Auth-surface scanning (forced browsing for admin/login panels, .git, env files)
**C. Session & account takeover**
9. Session/cookie theft — XSS, malware, AiTM phishing proxy (Evilginx-class)
10. Session fixation
11. Missing/broken revocation (logout doesn't invalidate; no server-side kill switch)
12. Concurrent session use from 2+ networks (theft indicator)
13. CSRF on state-changing auth endpoints
14. Weak cookie configuration (missing httpOnly/secure/SameSite, broad domain)
15. Excessive session lifetime / replay after logical expiry
16. Login from anomalous network (hosting/VPN/datacenter ASN, impossible travel)
16a. Successful login immediately after failures, from a new device/network, or to many accounts from one device (probable compromise/session farming)
16b. Dormant-account reactivation or concurrent use from incompatible device/network combinations
16c. Multi-step account-takeover chain: reset/recovery → login → factor/contact/session/API-key/OAuth change or high-value action
16d. Session/token used for a sensitive action from a different device/network than the authentication or step-up event
**D. Token attacks (JWT / opaque / refresh)**
17. `alg=none` / algorithm-confusion (RS256→HS256) acceptance
18. Weak or brute-forceable signing secret
19. Missing `exp` / `aud` / `iss` validation
20. Refresh-token theft; missing rotation and reuse detection
21. Token leakage — URLs, logs, Referer headers, localStorage exposed to XSS
**E. Passwordless / OTP / magic links**
22. Magic-link or OTP request flooding (email/SMS bombing; provider cost abuse)
22a. One source/account/device requests sends to many targets (enumeration, account farming, denial of wallet)
22b. Many distributed sources request sends to one target (victim bombing that bypasses per-IP limits)
22c. SMS/voice traffic pumping to premium, high-cost, unexpected-country, or sequential destination ranges
22d. Retry, parallel-request, resend, multi-channel fallback, or webhook-loop amplification causes duplicate paid sends
22e. Global provider spend/quota exhaustion blocks legitimate login, verification, or recovery traffic
22f. Send-to-verification conversion collapse (many billed sends with few successful OTP uses), including by provider/country/prefix
23. OTP / magic-link token brute force on the callback
24. Link/OTP interception (open redirects, email forwarding) and reuse
25. Long-lived or non-single-use login tokens
25a. Multiple simultaneously valid resend codes/links, or a race that redeems a single-use token more than once
**F. MFA**
26. MFA bypass routes (legacy API, remember-me, recovery flow that skips MFA)
27. Push fatigue / MFA prompt bombing
27a. OTP/MFA phishing relay or AiTM proxy (a correct code is used from a different session/device)
27b. Factor downgrade/channel-choice abuse (forcing SMS/voice/email fallback around a stronger factor or to increase cost)
28. Recovery-code brute force
29. Post-takeover factor enrollment / MFA reset hijack
29a. Support/help-desk assisted recovery or MFA reset approved without strong identity proof, dual control, audit, or delay
30. SMS factor SIM-swap exposure
30a. WebAuthn/passkey RP ID, origin, challenge, or user-verification validation failure; insecure password/SMS fallback bypasses the phishing-resistant factor
**G. OAuth / OIDC / SSO / SAML**
31. `redirect_uri` manipulation / open redirect → code theft
32. Missing `state` (CSRF) or missing PKCE on public clients
33. Authorization-code interception or replay
34. Account-linking confusion (auto-link on unverified email; IdP mix-up)
35. SAML signature wrapping / unsigned assertion acceptance
36. Over-broad JIT provisioning or role-mapping abuse
36a. OAuth/OIDC replay from missing `nonce`; device-authorization phishing/user-code brute force or abusive polling
**H. Account lifecycle & recovery**
37. Password-reset poisoning (Host-header / URL injection in reset links)
38. Reset-token brute force or predictable tokens
39. Email/phone change without re-auth + no notification to the old channel
40. Signup abuse — bots, disposable emails, mass account creation
40a. Account pre-hijacking: unverified signup or identifier change is later auto-linked to the victim's OAuth/SSO identity
40b. Email/phone Unicode, case, punctuation, or canonicalization mismatch creates duplicate/colliding identities or bypasses per-target limits
40c. Dormant-account takeover followed by recovery/contact changes or rapid sensitive activity
41. Lockout abuse as targeted DoS against victim accounts
**I. API & machine-to-machine auth**
42. API key leakage (repo history, client bundle, logs)
43. Over-privileged keys; missing scopes/rotation/IP allowlisting
44. Invalid-key spray / key brute force on API endpoints
45. Unauthenticated internal/service endpoints reachable from outside
45a. Spoofed trusted proxy/identity headers or fail-open auth middleware makes an external request appear internal/authenticated
**J. Availability**
46. Login-endpoint DoS (expensive password-hash amplification)
47. Session-store / signup-flood storage exhaustion
48. Email/SMS provider quota exhaustion (cost DoS via auth flows)
48a. Voice/WhatsApp/push fallback or provider retry storm multiplies auth-delivery cost
48b. No tenant/global daily volume or spend ceiling, alert, kill switch, or reserved quota for legitimate recovery
**K. Transport, storage & secrets**
49. Weak or unsalted password hashing (MD5/SHA-1, low work factor)
50. Missing TLS/HSTS; cookies transmittable over HTTP
51. Auth secrets committed to the repo or baked into client bundles
52. Credentials/tokens captured in application logs and traces
**L. Post-auth privilege boundary (brief — link to a future authorization model)**
53. Privilege escalation via client-controlled token claims (role tampering)
54. IDOR on account-management endpoints (other users' sessions/profile/factors)
54a. Missing step-up/re-authentication for factor/contact/API-key/OAuth-grant/export/payment/admin changes
**M. Detection, telemetry & third-party control-plane integrity**
55. Auth requests are traced but expected success/failure/send/security-change events are missing (instrumentation coverage drift)
56. SecureNow exporter/collector/ingestion outage, queue saturation, clock skew, duplicate delivery, or deployment instance silently stops emitting
57. Provider delivery/fraud callbacks or usage events stop, diverge sharply from accepted sends, or are forged/replayed
58. Messaging/identity-provider account or API credential compromise changes services/senders/geo policy/fraud protection or sends outside the app
59. Provider volume/spend shows sends with no matching app `attempt_id` (out-of-band use or compromised provider credential)
60. Alert rule is disabled/edited, notification delivery fails, or a required rule never ran/was not recently validated
61. Forged/replayed custom security events or a compromised SecureNow runtime ingest key poisons detections
62. Rate-limit/detection evasion via alternate routes, encoding/case aliases, IPv6/IP rotation, residential proxies, spoofed forwarding headers, or parallel requests
63. Unsafe automated remediation blocks a shared egress, victim account, or bombed recipient and causes denial of service
---
## Phase 3 — Map every modeled threat to SecureNow detection + mitigation
Classify each threat with exactly one coverage badge:
- 🟢 **COVERED** — detectable + mitigable with SecureNow today (existing rule, or a rule
you provide the SQL for, on telemetry that is already flowing).
- 🟡 **PARTIAL** — works after the customer adds instrumentation (`track()` events or
`guard()`), or the detection is inherently false-positive-prone (notify-only).
- 🔴 **GAP** — SecureNow cannot detect or mitigate this today. **Still include it**: give
the app-level fix (in the code-findings report), then add the line *"Requires SecureNow
team — contact your SecureNow account contact (or in-dashboard support) to request support
for this threat."* Collect all gaps in the detection report's "Known gaps & SecureNow
feature requests" section.
Also give every row exactly one **signal-source class**; do not confuse "a rule can be written"
with "the required data already exists":
- `NATIVE_TRAFFIC` — SecureNow HTTP spans already contain the signal; a SQL alert can be created
now with no app event.
- `APP_EVENT` — SecureNow can create the SQL alert, but it works only after the app emits the
specified privacy-safe `track()` event. Usually 🟡 until that event is verified in production.
- `PROVIDER_EVENT` — SecureNow can create the alert only after a signed provider webhook, audit-
log poller/export, or usage adapter emits the specified event. Provider activity that bypasses
both the app and adapter is invisible.
- `EXTERNAL_MONITOR` — the signal must come through an independent health/control-plane path.
Examples: complete telemetry outage, notification-channel failure, and alert scheduler health.
If no such integration exists, classify 🔴 GAP rather than manufacturing an in-band heartbeat.
- `APP_OR_PROVIDER_CONTROL` — the item is a prevention/kill-switch requirement rather than a
SecureNow detection/enforcement capability (for example global spend breaker or target quota).
SecureNow may alert and contain source IPs, while the app/provider owns the actual control.
Code-level fixes that are the app's own responsibility (cookie flags, PKCE, hashing
parameters…) go in the mitigation column as **app fix** — they coexist with SecureNow
controls, they don't replace detection — and they are detailed in the **code-findings**
report (App / config fixes), cross-linked from the matrix row.
Use **only** the SecureNow building blocks below, and only the flags/columns and `track()` shape the
**installed** SDK/CLI from Phase 0.5 actually exposes. Never invent CLI flags or SQL columns.
Reuse automatic/existing event names; proposed custom names are allowed only when the installed
`track(type, props)` accepts arbitrary string types, and must be labeled as instrumentation work.
### 3a. Instrumentation (what detections feed on)
```js
// Sessions: one line — emits `session.seen` and enforces revocations
const securenow = require('securenow/sessions');
app.use(securenow.guard());
// Events: fire-and-forget in your auth handlers — never throws
const { track } = require('securenow/events');
track('auth.login.failure', { userId, sessionId, ip, attributes: { reason: 'bad_password' } });
track('auth.login.success', { userId, sessionId, ip });
```
Canonical event taxonomy — rules match these **exact strings**. Confirm the installed
`securenow/events` `track()` signature; distinguish automatic/existing app events from the rows
explicitly labeled **propose**, which the customer must instrument:
| Event | Emit when |
|---|---|
| `auth.login.success` / `auth.login.failure` | every login attempt resolves |
| `auth.signup` | account created |
| `auth.logout` | explicit logout |
| `auth.magiclink.requested` / `auth.otp.requested` | passwordless link/code accepted for issuance; include privacy-safe flow/channel/target/cost dimensions below |
| `auth.otp.failure` | wrong code submitted |
| `auth.password.reset.requested` / `auth.password.reset.completed` | recovery flow |
| `auth.mfa.challenge` / `auth.mfa.failure` / `auth.mfa.enrolled` | MFA lifecycle |
| `auth.email.changed` | contact-channel change |
| `auth.account.locked` | lockout triggered |
| `session.seen` | automatic via `guard()` |
| `api.sensitive.flow` | **reuse the cross-model event** after a provider accepts/bills an auth send (`flow=otp_send|magiclink_send|password_reset_send|verification_send|mfa_send`) |
| `api.ratelimit.exceeded` | **reuse the cross-model event** when an auth send/check/account/device/global quota or cool-down rejects the action |
| `auth.verification.completed` | propose when no existing success event represents OTP/email/phone verification; needed for send-to-success conversion detection |
| `auth.security.change` | propose for password/contact/factor/recovery-code/session/API-key/OAuth-grant changes; include `action`, `outcome`, actor/subject IDs, session/device hashes, and whether step-up occurred |
| `auth.recovery.action` | propose for self-service and support-assisted recovery/MFA reset lifecycle (`requested|approved|denied|completed`) with method and approver-role—not approver PII |
| `auth.provider.activity` | propose only for a signed provider webhook/audit/usage adapter: accepted/delivered/failed/fraud-blocked send, credential/config/geo-policy change, or out-of-band send |
| `auth.telemetry.coverage` | optional independently-produced coverage/check result; never claim an in-process event can detect failure of its own exporter |
For every auth-message event, use only privacy-safe, bounded attributes. Never emit a raw email,
phone number, OTP, token, message body, or full unbounded URL. Use a keyed/HMAC or salted stable
`recipient_hash` (plain SHA-256 of a guessable phone/email is insufficient), plus applicable
`flow`, `channel`, `provider`, `destination_country`, coarse `destination_prefix`, `cost_units`,
`segments`, `provider_outcome`, `attempt_id`, `device_hash`, and `reason`. Emit
`api.sensitive.flow` **after provider acceptance** so it represents a paid/consumed unit; emit the
request event separately so rejected requests are not mistaken for spend. `cost_units` must use a
documented consistent unit (for example provider billing currency minor units), never floating
point. Correlate requests, sends, and completions with an opaque `attempt_id`.
For chained detections, use a stable opaque `enduser.id`, `session.id`, and bounded hashes for
device/target; include `auth_method`, `action`, `outcome`, `step_up`, `request_id`/`attempt_id`, and
the initiating/current IP. Do not put role names, support notes, raw identifiers, provider secrets,
or arbitrary JSON into attributes. Provider adapters must verify webhook signatures or authenticate
their audit API before emitting `auth.provider.activity`; otherwise forged input would poison the
detection layer. Protect and rotate the SecureNow runtime ingest key, and flag duplicate/replayed
event IDs at the adapter/app boundary.
Ingest enriches every event IP with **ASN/org** (`client.asn`, `client.as_org`), enabling
network-level detections (distributed attacks, hosting/VPN logins) with no extra code.
HTTP traffic (status codes, paths, IPs) is captured automatically once the app runs under
`securenow run` / `securenow/register` / `securenow init` — traffic-based rules need no
events at all.
### 3b. Detection rules — SQL conventions
Two query shapes. Both **must** keep the tenant scope and **must** select an `ip`
column (per-IP aggregation is what remediation/auto-block keys on). **The tenant-scope
column differs by table** — using the wrong one fails with `UNKNOWN_IDENTIFIER`:
- **logs** (`signoz_logs.distributed_logs_v2`) → `resources_string['service.name'] IN (__USER_APP_KEYS__)`
- **traces** (`signoz_traces.distributed_signoz_index_v3`) → `` `resource_string_service$$name` IN (__USER_APP_KEYS__) ``
When grouping by `ip`, add `HAVING ip != '' AND …` so rows with no client IP don't
aggregate into an empty-key bucket.
**Events-based** (auth events from `track()`/`guard()` — query the **logs** table):
```sql
SELECT
attributes_string['http.client_ip'] AS ip,
count() AS failures,
uniqExact(attributes_string['enduser.id']) AS distinct_accounts
FROM signoz_logs.distributed_logs_v2
WHERE resources_string['service.name'] IN (__USER_APP_KEYS__)
AND attributes_string['event.type'] = 'auth.login.failure'
AND timestamp >= now() - INTERVAL 15 MINUTE
GROUP BY ip
HAVING ip != '' AND failures >= 10
```
Useful event attributes: `event.type`, `enduser.id`, `session.id`, `http.client_ip`,
`client.asn`, `client.as_org`.
**Traffic-based** (HTTP spans, no events needed):
```sql
WITH coalesce(nullIf(attributes_string['http.client_ip'], ''), nullIf(attributes_string['net.peer.ip'], ''), nullIf(attributes_string['network.peer.address'], '')) AS client_ip
SELECT client_ip AS ip, count() AS hits
FROM signoz_traces.distributed_signoz_index_v3
WHERE `resource_string_service$$name` IN (__USER_APP_KEYS__)
AND timestamp >= now64(9) - INTERVAL 15 MINUTE
AND ts_bucket_start >= toUInt64(toUnixTimestamp(now() - INTERVAL 15 MINUTE)) - 1800
AND kind = 2
AND attributes_string['http.target'] LIKE '/api/auth/%'
GROUP BY ip
HAVING hits >= 20
```
### 3b.1 Required authentication-abuse detection set
When the relevant surface exists, the report is incomplete unless it creates or identifies an
existing rule for **each** item below. If telemetry is missing, mark the row 🟡 PARTIAL and give
the exact `track()` call + file:line needed. If the threat is genuinely absent, mark it N/A with
evidence. Do not collapse these into one generic "OTP flood" rule:
1. **Auth-route request burst per IP** — traffic-only POST rate on each login/signup/reset/OTP/
magic-link/MFA-send route; separate cheap requests from expensive hash/provider paths.
2. **One source → many targets** — paid sends and request events grouped by IP and, where
available, account/device; alert on high count + high `uniqExact(recipient_hash)`.
3. **Many sources → one target** — events grouped by `recipient_hash`, with total sends and
`uniqExact(ip)`/ASN/device. This is the required victim-bombing/distributed-bypass rule; the
recipient hash is for correlation only and must never appear as raw PII in the report.
4. **Destination pumping** — send count/cost grouped by destination country + coarse prefix +
provider, returning the contributing IPs. Flag new/unexpected/high-cost geographies,
sequential/prefix concentration where available, SMS/voice fallback, and provider fraud-block
outcomes. Country/prefix policy must come from the app/provider configuration, not invention.
5. **Spend/quota tripwire** — per-IP and per-account cost, plus a **global/tenant aggregate** over
short and daily windows. Because SecureNow remediation is IP-oriented, implement the global
rule as a two-stage query: first prove the aggregate budget is crossed, then return the top
contributing non-empty IP rows. It is notify/manual-containment first; never auto-block every
contributor solely from a global anomaly.
6. **Send → successful verification conversion collapse** — minimum-sample ratio by IP/device/
provider/country/prefix (for example sends vs `auth.verification.completed`, OTP login success,
or reset completion). A large send count with near-zero completions is a pumping indicator;
ship test-first and avoid alerting on tiny samples.
7. **Resend/retry/fallback amplification** — repeated provider-accepted sends sharing an
`attempt_id`/recipient/flow, parallel requests, multiple active codes, or channel escalation
(SMS → voice) faster than policy allows.
8. **Quota/cool-down ceiling abuse** — `api.ratelimit.exceeded` grouped by IP plus scope/reason,
and separately by target/account/device hash, so persistent distributed pressure is visible.
9. **Credential attack in both directions** — failures from one IP against many accounts **and**
failures from many IPs against one account; include success-after-failures and one device/IP
successfully entering many accounts.
10. **Token/session replay** — refresh-token reuse, duplicate OTP/link redemption, concurrent
incompatible sessions, and MFA/OTP completed from a different session/device than initiated.
11. **Multi-step account-takeover sequences** — correlate by durable user/account and time-order
reset/recovery/contact/factor/login/session events, then return the triggering/current IP.
Cover at minimum recovery/reset → login → factor/contact/API-key/OAuth change, success after a
failure burst, dormant-account login → sensitive action, and authentication on one device/
network → sensitive action on another. Use ClickHouse conditional aggregates/sequence
functions only after validating them with the installed rule dry-run command.
12. **Post-authentication security changes** — unusual factor/contact/recovery-code/API-key/OAuth-
grant/session changes, missing `step_up=true`, many accounts changed from one device/IP, and
rapid sensitive action after the change. These are `APP_EVENT`; SecureNow cannot infer a
factor reset or API-key creation from generic HTTP 200 traffic alone.
13. **Recovery/support abuse** — support-assisted recovery volume per operator/source/target,
repeated denied→approved attempts, approval outside policy/hours, one operator resetting many
accounts, and recovery completed without required dual control/delay. Use opaque operator IDs
and notify/review first; never auto-block a victim based only on being targeted.
14. **Evasion & identity-quality** — route-normalized counts across aliases/API versions, raw
socket-vs-forwarded IP disagreement from untrusted proxies, IPv4/IPv6 rotation, per-ASN
breadth, high `uniqExact(ip)` with stable device/account/target, and parallel requests that
exceed the logical limit while each IP remains below it.
15. **Provider control-plane/out-of-band activity** — after provider audit/usage events exist,
detect fraud-protection/geo/sender/service/credential changes, unexpected actor/location,
provider sends without a matching app `attempt_id`, delivery/fraud failure spikes, bounce/
complaint changes, unexpected SMS segments or voice duration, and provider spend/volume
exceeding app-recorded accepted sends. Mark `PROVIDER_EVENT`; without that adapter the row is
🔴 GAP.
16. **Detection coverage and health** — while traces still flow, compare auth-route request counts
with expected auth events; compare accepted sends with provider outcomes; detect missing
deployment-instance/event coverage, duplicates, excessive event lag, and clock skew. A total
telemetry/collector outage, alert-scheduler failure, or notification-channel failure requires
an independent external monitor/control-plane signal and is 🔴 GAP if none exists.
17. **Event/integration integrity** — duplicate/replayed event IDs or `attempt_id`s, impossible
timestamps/ordering, missing required attributes, forged provider callbacks, one ingest key
suddenly emitting for unrelated deployments, and runtime-key creation/rotation anomalies.
SQL can catch malformed/replayed ingested events; webhook authentication and key lifecycle are
app/provider/control-plane controls and must not be overstated.
18. **Rule/control-plane drift** — independently compare the required rule manifest with
`securenow alerts rules --json`, rule status/mode/schedule/channels, recent execution/history,
and notification delivery. This is an operator/external health check, not a traffic SQL rule;
classify `EXTERNAL_MONITOR` or GAP.
Thresholds must be explicit and justified from an existing policy/provider limit or a measured
baseline. If neither exists, choose a conservative test-mode starting threshold, label it
"baseline required", and include the 3–7 day tuning workflow. For target/global/conversion rules,
the mitigation is notify + app/provider circuit breaker or target/account quota; do not pretend an
IP block fixes a distributed attack. **An IP-only rate limit earns at most PARTIAL coverage** for
items 22a–22f/48/48a/48b.
Every rule in this set must say whether SecureNow can create it **now**, can create it **after
instrumentation/provider ingestion**, or **cannot currently create it**. For creatable rules emit
the complete SQL → file → `securenow alerts rules create` → dry-run unit. For gaps, do not output
fake SQL; name the missing signal/integration and the interim app/provider/external-monitor control.
### 3c. Mitigation commands — the full SecureNow toolbox (select per threat)
Once a threat is confirmed, **choose the narrowest effective mitigation(s) from ALL of these**
and combine them (e.g. rate-limit `/api/login` + block the worst IPs + challenge a NAT egress).
Re-check every command/flag against the installed SDK in Phase 0.5 (`securenow <cmd> --help`);
annotate `# requires securenow >= <ver>` if absent. Scope by **app / env / route / method / IP /
duration** to avoid hitting real users.
| # | Mitigation | Command (ready-to-copy) | Use / scope |
|---|---|---|---|
| 1 | **Free firewall (network)** | `securenow firewall enable --app <APP_KEY> --env production` · `securenow run --firewall-only` · test `securenow firewall test-ip <ip> --path /x --method GET` | 500k+ known-bad IPs, hourly refresh; drop scanners before the app. No app change. |
| 2 | **Exploit-signature instant block** | enable the `instant` config on the system SQLi/XSS/RCE signature rules (dashboard / MCP `securenow_alert_rule_instant_update`); custom rule → create with `--execution-mode instant` | synchronous ~2.6s block of the matching request (payload injection). Don't duplicate pattern SQL. |
| 3 | **IP block — global** | `securenow blocklist add <ip> --app <APP_KEY> --env production --reason "..."` | confirmed-malicious source, all routes. |
| 4 | **IP block — scoped to route (+ method)** | `securenow blocklist add <ip> --route /admin* --mode prefix --method ALL --app <APP_KEY> --env production --reason "..."` (`--mode exact\|prefix\|regex`, `--method GET\|POST\|…\|ALL`) | block an IP only on sensitive paths (e.g. `/api/auth/*`, `/admin*`); least collateral. |
| 5 | **IP block — temporary / time-boxed** | `securenow blocklist add <ip> --duration 24h --reason "..."` (`30m`,`24h`,`7d`) · reverse `securenow blocklist unblock <id> --reason "..."` | auto-expiring containment; audit-preserving unblock. |
| 6 | **Rate limit — per IP** | `securenow ratelimit add <ip> --limit 100 --window 1m --duration 24h --reason "..."` | throttle one abusive client across the app. |
| 7 | **Rate limit — per route (all clients, per-IP budget)** | `securenow ratelimit add --route /api/auth/reset --mode prefix --method POST --limit 5 --window 1m --key-by ip` | cap an expensive/abusable endpoint (login, reset, OTP request) for everyone, budgeted per IP. |
| 8 | **Rate limit — per route + IP** | `securenow ratelimit add <ip> --route /api/login --mode exact --method POST --limit 5 --window 1m --duration 24h` · NL `securenow ratelimit from-text "rate limit /api/login to 5/min for 24h" --yes` · test `securenow ratelimit test <ip> --path /api/login --method POST` | precise throttle of one client on one route. |
| 9 | **CAPTCHA / proof-of-work challenge** | `securenow challenge add --route /login --difficulty 16 --clearance 30m` (route-wide) **or** `securenow challenge add <ip> --route /api/search --difficulty 18 --clearance 30m` · test `securenow challenge test <ip> --path /login --method GET` | bot login/signup/scraping abuse from **shared / NAT / CGNAT** egress — a human passes once, a script can't. Prefer over a hard block when real users share the IP. |
| 10 | **Auto-block (risk-scored)** | `securenow automation defaults --yes` (≥95→7d, 90–94→72h, 85–89→24h) · custom `securenow automation create --conditions '[...]' --actions '[...]'` · preview `securenow automation dry-run <id>` | hands-off blocking by risk score; actions include block / rate_limit / requireCaptcha. |
| 11 | **Session revocation** | `securenow revoke session <id> --reason "..."` / `securenow revoke user <id>` / `revoke list` / `revoke restore <id>` (SDK `securenow/sessions` `guard()` / `isRevoked()`) | session theft / account takeover — kill the stolen session, not the IP. |
| 12 | **Trusted IP (suppress)** | `securenow trusted add <ip> --label "Office VPN / partner / monitor"` | stop false positives from known-good infra — suppresses detection **and** mitigation. NOT deny-by-default. |
| 13 | **Allowlist (deny-by-default)** | `securenow allowlist add <ip> --label "..." --reason "..."` ⚠️ once any entry exists, ONLY listed IPs reach the app | lockdown of an internal/admin-only surface. Never for a public app. |
| 14 | **False-positive exclusion** | `securenow fp create --conditions '[...]' --rule-scope this_rule --reason "..."` · `securenow fp mark <notification-id> <ip> --rule-scope this_rule` · preview `securenow fp dry-run --conditions '[...]'` | keep a noisy rule quiet without weakening it. |
| 15 | **App / config / code fix (primary for root cause)** | *described in the Code-Findings report, never auto-applied* | the actual fix (cookie flags, PKCE/`state`, hashing parameters, reset-token single-use, secret rotation, retire dev backdoor). SecureNow contains; the fix removes. |
**Choosing per threat** — by **confidence**: exploit-signature/exact IoC → instant-block or
block; probable bot on shared egress → **challenge**; noisy/legit-mixed traffic (brute-force /
enumeration / flood thresholds) → **rate-limit (test-mode first)**; session compromise →
**revoke**; known-good noise → **trusted / fp**. By **blast radius**: always scope to the
narrowest `route`/`method`/`IP`/`duration` that stops the abuse; on NAT/CGNAT/shared IPs prefer
challenge/rate-limit over a hard block. Always pair an edge mitigation with the **app/config fix**
(Code-Findings report) when SecureNow can only contain the actor. (All commands are verified
against the installed SDK in Phase 0.5.)
For OTP/magic-link/reset/verification/MFA delivery, the app/config fix must be concrete: enforce
atomic shared counters **before** the paid provider call (per target + account + device + IP, with
ASN/prefix/tenant/global backstops); exponential resend delay; one active code/link at a time;
idempotency for parallel/retried requests; generic constant-behavior responses; destination
country/prefix policy; provider fraud protection; daily spend/volume budget with a kill switch and
reserved capacity for legitimate recovery. Prefer a phishing-resistant factor over SMS/voice and
do not expose a costlier fallback until policy permits it. Never recommend account lockout as the
only control, because an attacker can turn it into targeted denial of service.
Responses must be **victim-safe**. A bombed recipient or attacked account is not the malicious
actor: suppress/coalesce duplicate sends, preserve a recovery path, notify through an already-
verified channel, and rate-limit/challenge contributing sources. On NAT/CGNAT or uncertain source
identity, prefer scoped challenge/rate-limit and human review over a hard block. A global cost
tripwire should degrade gracefully (pause the expensive channel/provider/geo, preserve passkey or
other safe authentication, reserve emergency recovery capacity) and must not automatically expose
a costlier fallback such as voice. SecureNow can trigger/notify and contain IPs; the app/provider
must implement target/account budgets, channel switching, provider kill switches, and reserved
quota.
### 3d. Testing every detection and mitigation
Only test against apps/environments the user owns; prefer `--env local`/staging. For
synthetic source IPs use TEST-NET ranges (`192.0.2.0/24`, `198.51.100.0/24`,
`203.0.113.0/24`).
```bash
# Synthetic auth events — exercise an events-based rule end to end
for i in $(seq 1 12); do
securenow event send auth.login.failure --user victim@example.com \
--session test-$i --ip 203.0.113.99 --attrs reason=bad_password,test=true
done
# Paid auth-send abuse: one source -> many privacy-safe synthetic targets
for i in $(seq 1 25); do
securenow event send api.sensitive.flow --ip 203.0.113.50 \
--attrs flow=otp_send,channel=sms,recipient_hash=test-target-$i,cost_units=1,destination_country=ZZ,test=true
done
# Distributed victim bombing: many sources -> the same synthetic target hash
for i in $(seq 1 12); do
securenow event send api.sensitive.flow --ip 198.51.100.$i \
--attrs flow=password_reset_send,channel=email,recipient_hash=test-victim,cost_units=1,test=true
done
# Quota rejection / cool-down pressure
for i in $(seq 1 12); do
securenow event send api.ratelimit.exceeded --ip 203.0.113.51 \
--attrs route=/api/auth/otp,scope=per_target,reason=send_cooldown,test=true
done
# Multi-step ATO sequence on one opaque synthetic user
securenow event send auth.password.reset.completed --user test-user --session reset-1 --ip 203.0.113.60 --attrs test=true
securenow event send auth.login.success --user test-user --session session-2 --ip 203.0.113.61 --attrs method=password_reset,test=true
securenow event send auth.security.change --user test-user --session session-2 --ip 203.0.113.61 --attrs action=mfa_removed,step_up=false,outcome=completed,test=true
# Provider adapter signal: synthetic out-of-band paid send
securenow event send auth.provider.activity --ip 203.0.113.62 \
--attrs activity=send_accepted,flow=otp_send,attempt_id=provider-only-test,matched_app_attempt=false,cost_units=1,test=true
# Validate a rule query without waiting for the schedule
securenow alerts rules test <RULE_ID> --mode dry_run --wait
# Traffic-based rules — simulate, then check the pipeline
securenow test-span "threat-model.smoke"
securenow forensics "failed logins by IP in the last hour" --env production
# Mitigation verification
securenow firewall test-ip 203.0.113.99 --app <APP_KEY> --env production
securenow ratelimit test 203.0.113.99 --path /api/login --method POST
securenow revoke list
# Confirm + clean up
securenow notifications list --limit 10
securenow blocklist list # then: securenow blocklist unblock <id> --reason "threat-model test"
```
Every 🟢/🟡 threat row in the report must have a concrete test recipe (commands + expected
outcome: which rule fires, which notification appears, what the mitigation does).
---
## Phase 4 — Build the ready-to-copy detection units
Treat `node_modules/securenow` + the `--help` output from Phase 0.5 as the source of truth for
every flag, SQL column, `track()` signature, and automatic event. For **each** modeled threat that becomes a detection,
emit a **complete, copyable unit** — never a fragment. For each rule emit, in order: the SQL, a
line saving it to `rules/<name>.sql`, the full create command, the dry-run test. In Markdown
each is its own fenced block (so it copies cleanly). Example:
````markdown
**Rule: Auth — failed-login brute force (single IP)** · 🟢 COVERED · OWASP A07 / CWE-307 · high
```sql
-- rules/auth-bruteforce-single-ip.sql
SELECT
attributes_string['http.client_ip'] AS ip,
count() AS failures,
uniqExact(attributes_string['enduser.id']) AS distinct_accounts
FROM signoz_logs.distributed_logs_v2
WHERE resources_string['service.name'] IN (__USER_APP_KEYS__)
AND attributes_string['event.type'] = 'auth.login.failure'
AND timestamp >= now() - INTERVAL 15 MINUTE
GROUP BY ip
HAVING ip != '' AND failures >= 10
```
```bash
securenow alerts rules create \
--name "Auth: failed-login brute force (single IP)" \
--sql @rules/auth-bruteforce-single-ip.sql \
--apps <APP_KEY> --severity high --schedule "*/15 * * * *" \
--nlp "single IP with 10+ failed logins in 15 minutes"
securenow alerts rules test <RULE_ID> --mode dry_run --wait # validate before it runs live
```
````
The exact flags must match `securenow alerts rules --help` from Phase 0.5. Save each rule's SQL
to `rules/<name>.sql` so `--sql @rules/<name>.sql` works. Keep the SQL conventions from 3b
(tenant scope + `ip` column + `HAVING ip != ''`). **Note pre-existing/system rules** discovered
in Phase 0 instead of duplicating them. Injection-class / exploit-signature threats reference the
**system signature rules + `instant.block`**, not duplicate SQL. If the installed SDK lacks a
flag this prompt references, emit the rule but annotate it `# requires securenow >= <version>`.
### Test mode for false-positive-prone rules — ship `--mode test` first
Alert rules have a lifecycle **mode**: `test` = **detect-only, NO mitigation** vs `prod` = full
(mitigation / auto-action armed) — plus a **status** (`Active | Disabled | Paused`). Manage with:
```bash
securenow alerts rules update <RULE_ID> --mode test # detect-only: fires notifications, takes NO action
# …observe real traffic for several days; tune the threshold; add securenow fp exclusions for any FPs…
securenow alerts rules update <RULE_ID> --mode prod # promote: arm the mitigation / auto-action
securenow alerts rules update <RULE_ID> --status Paused # or --enable / --disable / --pause shortcuts
```
**Rule of thumb:** any detection that can **false-positive** — heuristic thresholds (brute-force /
flood / enumeration / signup counts), broad patterns, anomaly / volume / hosting-ASN-login rules,
anything tuned to YOUR traffic — must ship in **`--mode test` first**. Run it detect-only for
**3–7 days of real traffic**, review what it flags, raise/lower the threshold and add `securenow
fp` exclusions for legitimate hits, then `--mode prod` to arm mitigation. Only **high-precision**
rules (exploit-signature SQLi/XSS/RCE matches, exact-match IoCs, known-bad ASN hits) may go
straight to `prod`. **Tag every rule `test-first` or `prod-ready`** and say why. (`securenow alerts
rules test <id> --mode dry_run --wait` is the separate one-off *query* validation — run it before
either mode.)
For the **mitigation** side, use the full toolbox from 3c: every per-threat mitigation is itself
a ready-to-copy command (with `<APP_KEY>` substituted) plus its reversibility note.
---
## Phase 5 — Write the deliverables (two tracks, four files)
Write all four files into `threat/01-authentication/`. The two tracks cross-link each other:
the detection report's gap and instrumentation rows link to the relevant code finding, and each
code finding links back to the detection-report row it backs.
### 5a. Detection & Mitigation report — `authentication-detection-mitigation.{md,html}`
The **operational runbook**: what to run in SecureNow. It must work for two readers at once:
an owner who needs to understand risk and next actions in five minutes, and an engineer who needs
the exact SQL/commands. Put plain-language decisions first and dense technical reference later.
### Plain-language writing contract
- Use short sentences and define unavoidable security terms on first use. Do not lead with OWASP,
CWE, SQL, or SDK vocabulary.
- Every actionable threat has a one-sentence summary in this exact shape:
**"An attacker can <concrete action and impact>. SecureNow <sees/receives> <observable signal>,
detects <threshold/pattern>, and <alerts/contains> with <specific response>. Your app/provider
must <root-cause fix or prerequisite>."**
- Never say merely "SecureNow detects suspicious activity." Name what data it sees, how the rule
decides, the threshold/window, what notification appears, and what response is safe.
- Keep **Detect**, **Mitigate**, and **Fix** distinct: detection notices the behavior; mitigation
contains the current actor/session; the app/provider fix removes the underlying weakness.
- State prerequisites and limitations in visible prose: "works now from HTTP traffic," "needs this
event," "needs provider data," or "SecureNow cannot see this without an external monitor."
- Tailor every scenario to routes, mechanisms, providers, limits, and code actually found in THIS
project. Never use a generic hacker story when repository evidence supports a specific one.
Sections, in order (same content in .md and .html; HTML uses the reader-first components in §5c):
1. **Executive summary / security posture** — a 3–5 sentence plain-language verdict, stats line
(threats modeled · covered · partial · gaps · rules to create · mitigations), top 3 attack
stories for this stack, installed `securenow` version + app key + firewall state. Explicitly
answer: "What is protected now? What becomes protected after TODOs? What remains outside
SecureNow?"
2. **Start here — prioritized TODO board** — deduplicate every action from findings, missing
instrumentation, rules, mitigations, tests, and gaps into one ordered list. Group into
`DO NOW`, `NEXT 7 DAYS`, `LATER / HARDENING`, and `ALREADY IN PLACE`. Every TODO contains:
stable ID; action-oriented title; why it matters; owner (`SecureNow`, `App`, `Provider`, or
`External monitor`); priority; effort `S|M|L`; prerequisite; exact file:line or copyable command;
expected security outcome; verification/test; rollback/reversal; and links to its scenario,
rule, and code finding. Never duplicate the same work under multiple threats.
3. **How SecureNow helps — at a glance** — five plain-language lanes with counts and links:
`Protected now from traffic`, `Protected after app events`, `Protected after provider data`,
`Needs an external monitor`, and `App/provider prevention`. For each lane explain what data
SecureNow sees, one concrete example from this app, what it can alert/mitigate, and what it
cannot do. Include a small flow:
`Attacker action → HTTP/event/provider signal → SecureNow SQL rule → notification → scoped
response → permanent app/provider fix`.
4. **Attack scenarios — what happens and how we stop it** — one narrative scenario card for every
modeled (non-N/A) threat. The highest-risk/actionable cards appear first; low-risk/reference
cards may be collapsed in HTML. Each card contains, in this order:
- threat title, severity, coverage, signal-source class, readiness (`works now | needs event |
needs provider | external gap`) and linked rule/finding IDs;
- **Attack scenario** — 2–4 sentences beginning "An attacker can…", naming entry point,
sequence, victim/business impact, and why current controls do or do not stop it;
- **How SecureNow detects it** — 2–4 sentences naming automatic trace or exact event/provider
signal, correlation key, threshold + window, rule name, mode, and resulting notification;
- **How SecureNow mitigates it** — exact safe action (rate-limit/challenge/block/revoke/notify),
scope and duration, whether automatic or human-approved, and how to reverse it;
- **What you still need to do** — app/provider/external-monitor root fix and instrumentation;
- **Definition of done** — observable test outcome and link to the copyable commands.
Include this style example, adapted to the real app rather than copied literally:
*"An attacker can rotate IP addresses while repeatedly requesting password-reset emails for one
victim, flooding the inbox and consuming provider quota. The app emits a keyed recipient hash;
SecureNow detects the same target receiving 12 sends from 10 IPs in 15 minutes and alerts on the
contributing sources. SecureNow can challenge or rate-limit those sources, while the app must
enforce an atomic per-target cooldown before calling the email provider."*
5. **SDK & environment** — installed SDK version (from `node_modules/securenow`), app key(s),
environment, firewall state, existing rules/automations/challenge rules (from Phase 0), system
signature rules present. Present a human-readable "Ready / Needs setup / Unknown" checklist
before the raw values.
6. **Threat → Detection → Mitigation matrix (technical reference)** — one row per modeled threat:
`# | Threat | OWASP/CWE | Coverage 🟢/🟡/🔴 | Signal source | Detection rule | Signal (threshold+window) | Schedule | Sev | Mode | Mitigation`.
`Signal source` is exactly one of `NATIVE_TRAFFIC`, `APP_EVENT`, `PROVIDER_EVENT`,
`EXTERNAL_MONITOR`, or `APP_OR_PROVIDER_CONTROL`; state "creatable now", "creatable after
instrumentation", or "not currently creatable" in the detection cell.
Each row's **Mitigation** cell must pick **specific, scoped mitigation(s) from the §3c
toolbox** (named layer + scope: route/method/IP/duration) — never a generic "block the IP."
The **Mode** cell tags each rule `test-first` or `prod-ready` per the §3c test-mode rule of
thumb. Then the "Out of scope" N/A list and the deferred-to-sibling rows. Severity ∈ {critical,
high, medium, low}.
7. **Detection rules to create** — each as the ready-to-copy unit from Phase 4 (SQL → save →
create → dry-run). **Mark each rule `test-first` or `prod-ready`**; for every `test-first`
rule include the `--mode test` → observe (3–7 days) → `--mode prod` promotion step. Injection-
class rows reference the **system signature rules + `instant.block`**, not duplicate SQL. Note
rules that already exist from Phase 0.
8. **Instrumentation the detections need** — only the `track('…')` events the rules above
consume, each as a copyable snippet; point to the code-findings report for *where* to add
them.
9. **Mitigation mechanisms** — render the **full §3c toolbox table** (1 Free firewall · 2 Exploit-
signature instant block · 3–5 IP block [global / route+method / temporary] · 6–8 rate-limit
[IP / route / IP+route] · 9 challenge · 10 auto-block · 11 session revocation · 12 trusted ·
13 allowlist · 14 fp exclusion · 15 app/config fix) + the "Choosing per threat" paragraph +
per-threat ready-to-copy mitigation command (scoped, `<APP_KEY>` substituted) with its
reversibility note.
10. **Implementation plan (copy-paste, ordered)** — the command-oriented expansion of the TODO
board: ① firewall + signature instant-block, ② add
instrumentation, ③ create rules — **FP-prone rules created in `--mode test`**, ④ enable
automations/challenge, ⑤ test, ⑥ verify, ⑦ **promote each `test-first` rule to `--mode prod`
after N days (3–7) of clean traffic**, ⑧ schedule the app/config fixes (from the code report).
Real commands, `<APP_KEY>` substituted.
11. **Testing & validation** — per-rule recipe: `securenow event send …` / `test-span` / dry-run
+ expected outcome + cleanup (TEST-NET IPs 192.0.2/198.51.100/203.0.113).
12. **Response runbooks** — per notification type: confirm TP → respond command (copy) → reverse
command (copy). Include victim-safe recipient bombing, shared-egress handling, provider-account
compromise, telemetry degradation, and multi-step ATO containment.
13. **Detection health & governance** — table for every rule:
`rule/id | owner | signal source | expected coverage/ratio | threshold source | mode | channel |
last dry-run | last synthetic test | FP budget | runbook | reversible action`. Include an
instrumentation coverage dashboard/query (traced auth requests vs auth events), provider send
vs outcome/app-attempt reconciliation, and explicit external checks for total ingestion,
scheduler, and notification-channel health. Never use an in-band heartbeat as sole proof that
the same ingestion path is healthy.
14. **Known gaps & SecureNow feature requests** — each 🔴: why not coverable, interim fix (link
to code report), and the "contact the SecureNow team" line.
15. **Appendix** — resolved SDK/CLI version, app key, environment, rule IDs created, date.
### 5b. Code Findings & Recommendations report — `authentication-code-findings.{md,html}`
State at top: *"Findings only — no application code was modified."* Apply the same plain-language
contract as §5a. Every finding must be understandable without reading its code snippet or knowing
OWASP terminology. Sections, in order (same content in .md and .html):
1. **Executive summary / code posture** — findings by severity (critical/high/med/low), top 3 code
risks, and a 3–5 sentence verdict answering what an attacker could achieve and which fixes
reduce the most risk first.
2. **Start here — code TODO board** — the code/config/instrumentation subset of the master TODO
board, deduplicated and ordered `DO NOW`, `NEXT 7 DAYS`, `LATER`, `ALREADY IN PLACE`. Each task
includes owner, priority, effort, file:line, concrete change, dependency, outcome, verification,
definition of done, and link to its finding + detection scenario.
3. **How the app and SecureNow work together** — explain in plain language: the app prevents and
emits business context; SecureNow observes traffic/events, detects patterns, notifies, and
contains actors/sessions; provider/external controls cover what neither can see. Include one
real example from this project and visible "SecureNow helps / App must fix" columns.
4. **Surface & inventory** — the Phase 1 inventory for authentication (mechanisms / endpoints /
session model / storage / MFA / recovery / existing limits / sensitive paths) plus the
auth-message cost/control table (paid call point, target source, cost/retry/fallback, every
quota dimension, fraud guard, global circuit breaker).
5. **Threat catalog** — the exhaustive Phase 2 catalog, including every letter-suffixed addition
(grouped, each tagged OWASP/CWE,
modeled or explicit N/A).
6. **Code-level findings (audit)** — a scan-friendly summary table
`# | Location (file:line) | Threat | OWASP/CWE | Sev | Issue | Recommended fix`, each with the
quoted 1–8 line snippet and the described fix (never applied). After the table, render one
finding card per issue (reuse the accessible `.scenario` `<details>` component with a stable
`finding-*` ID and appropriate filter data) with: **What is wrong**, **How an attacker could use it** (beginning "An
attacker can…"), **What SecureNow sees and detects**, **What SecureNow cannot fix**, **Exact
recommended change**, **Definition of done**, and cross-links to the rule/scenario/TODO. Do not
claim a code flaw is traffic-detectable when it has no observable signal.
7. **Strengths** — controls already present and correct (honest posture), phrased as protections
and the attacks they stop—not merely library/config names.
8. **App / config fixes (primary remediation)** — the config/code changes that remove the root
cause (described, not applied): cookie flags, PKCE/`state`, hashing parameters, reset-token
single-use, secret rotation, etc. Each linked to the detection-report matrix row it backs.
9. **Instrumentation recommendations** — the `track('…')` calls to add and the exact file:line
to add them (from Phase 1), so the detection rules light up. Separate app events from signed
provider adapters and independent external monitors; include runtime-key protection/rotation,
replay/deduplication, bounded attributes, and redaction requirements.
10. **Verification checklist / definition of done** — one checkbox-style row per TODO with test,
expected evidence, linked rule/finding, and status `not started | ready to test | verified`.
11. **Appendix** — files reviewed, resolved SDK version, date, link to the detection-mitigation
report.
### 5c. HTML skeletons — two self-contained files (offline; inline CSS + copy JS; no network)
Both HTML files share the `<head>` below and the script at the end of `<body>`. The HTML is a
reader-first report, **not a literal Markdown-to-HTML table dump**:
- Put the posture verdict, TODO board, SecureNow-help lanes, and attack/finding stories before
technical matrices and command appendices.
- Use semantic headings, `<article>`, `<details>/<summary>`, lists, buttons, and links. Do not use
color as the only meaning; every badge also has text. Maintain visible keyboard focus and valid
heading order.
- Keep prose lines readable (`max-width: 78ch`). Wrap every wide table in `.table-wrap`. The page
must work without JavaScript; JS only enhances copy/search/filter behavior.
- Add a sticky scenario toolbar with text search and filter buttons for `All`, `Do now`, `Works
now`, `Needs event`, `Needs provider`, and `Gap`. Cards carry `data-severity`, `data-coverage`,
`data-readiness`, and a normalized `data-search` string. Show a useful no-results message.
- Render the five highest-priority attack/finding cards expanded; use `<details>` for the rest so
the report remains scannable. Deep links must open at the correct stable ID.
- Wrap **EVERY** command/SQL block as `.cmd` so it gets a Copy button. Copy buttons have an
accessible label and status text.
- Add print styles that remove navigation/filter controls, expand all content in the generated
markup where practical, and keep TODO/scenario cards legible on white paper.
**Shared `<head>` + `<body>` shell + copy `<script>`** (identical for both files):
```html
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title><!-- "Detection & Mitigation — Authentication — SecureNow" OR "Code Findings — Authentication — SecureNow" --></title>
<style>
:root{--bg:#0f1419;--panel:#161c24;--panel2:#1b2330;--border:#26303d;--txt:#dbe3ec;--muted:#8b97a7;
--accent:#3ea6ff;--accent2:#16c79a;--crit:#ff5c6c;--high:#ff9f43;--med:#f7c948;--low:#8b97a7;
--ok:#16c79a;--info:#3ea6ff;--rev:#b388ff;}
*{box-sizing:border-box}html{scroll-behavior:smooth;color-scheme:dark}
body{margin:0;background:var(--bg);color:var(--txt);font:15px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}
:focus-visible{outline:3px solid var(--accent);outline-offset:2px;border-radius:4px}
code{background:#0b0f14;border:1px solid var(--border);border-radius:5px;padding:.08em .4em;font:13px/1.4 ui-monospace,"SF Mono",Menlo,Consolas,monospace;color:#9fe0c0}
.wrap{display:grid;grid-template-columns:240px 1fr;max-width:1280px;margin:0 auto}
nav{position:sticky;top:0;align-self:start;height:100vh;overflow:auto;padding:28px 18px;border-right:1px solid var(--border);background:var(--panel)}
nav .brand{font-weight:700;font-size:15px;letter-spacing:.3px}nav .brand span{color:var(--accent)}
nav .sub{color:var(--muted);font-size:12px;margin-bottom:22px}
nav a{display:block;color:var(--muted);padding:7px 10px;border-radius:7px;font-size:13.5px}
nav a:hover{background:var(--panel2);color:var(--txt)}
main{padding:36px 40px 80px;min-width:0;max-width:1040px;width:100%}
header.top h1{margin:0 0 6px;font-size:26px}header.top p{margin:0;color:var(--muted)}
.pill{display:inline-block;font-size:11px;font-weight:600;padding:3px 9px;border-radius:999px;border:1px solid var(--border);color:var(--muted);background:var(--panel)}
.stats{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin:26px 0 34px}
.stat{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:16px 18px}
.stat .n{font-size:26px;font-weight:700}.stat .l{color:var(--muted);font-size:12.5px;margin-top:2px}
section{margin:0 0 40px}
h2{font-size:18px;margin:0 0 14px;padding-bottom:8px;border-bottom:1px solid var(--border)}
h2 .num{color:var(--accent);font-weight:700;margin-right:8px}
.prose{max-width:78ch}.lead{font-size:16px;color:#c5d0dc;max-width:78ch}.muted{color:var(--muted)}
.table-wrap{width:100%;overflow:auto;border:1px solid var(--border);border-radius:12px;background:var(--panel)}
table{width:100%;border-collapse:collapse;font-size:13.5px;background:var(--panel);min-width:760px}
th,td{text-align:left;padding:11px 13px;border-bottom:1px solid var(--border);vertical-align:top}
th{background:var(--panel2);color:var(--muted);font-weight:600;font-size:12px;text-transform:uppercase;letter-spacing:.4px}
tr:last-child td{border-bottom:none}tr:hover td{background:#19212c}
.rid{font:12px ui-monospace,Menlo,Consolas,monospace;color:#7fd1ff;white-space:nowrap}
.b{display:inline-block;font-size:11px;font-weight:700;padding:2px 8px;border-radius:6px;white-space:nowrap}
.b.crit{background:rgba(255,92,108,.15);color:var(--crit);border:1px solid rgba(255,92,108,.35)}
.b.high{background:rgba(255,159,67,.13);color:var(--high);border:1px solid rgba(255,159,67,.32)}
.b.med{background:rgba(247,201,72,.13);color:var(--med);border:1px solid rgba(247,201,72,.32)}
.b.low{background:rgba(139,151,167,.13);color:var(--low);border:1px solid rgba(139,151,167,.32)}
.c{display:inline-block;font-size:11px;font-weight:700;padding:2px 8px;border-radius:6px;white-space:nowrap}
.c.cov{background:rgba(22,199,154,.13);color:var(--ok);border:1px solid rgba(22,199,154,.35)}
.c.part{background:rgba(247,201,72,.13);color:var(--med);border:1px solid rgba(247,201,72,.32)}
.c.gap{background:rgba(255,92,108,.15);color:var(--crit);border:1px solid rgba(255,92,108,.35)}
.owasp,.cwe{display:inline-block;font:11px ui-monospace,Menlo,Consolas,monospace;color:var(--accent);border:1px solid rgba(62,166,255,.3);border-radius:6px;padding:1px 6px;white-space:nowrap}
.cwe{color:var(--rev);border-color:rgba(179,136,255,.3)}
.m{display:inline-block;font-size:11px;font-weight:600;padding:2px 8px;border-radius:6px;border:1px solid var(--border)}
.m.block{color:var(--crit);border-color:rgba(255,92,108,.35)}.m.rate{color:var(--info);border-color:rgba(62,166,255,.35)}
.m.challenge{color:var(--accent2);border-color:rgba(22,199,154,.35)}.m.firewall{color:var(--ok);border-color:rgba(22,199,154,.35)}
.m.signature{color:var(--crit);border-color:rgba(255,92,108,.35)}.m.notify{color:var(--muted)}.m.appfix{color:var(--high);border-color:rgba(255,159,67,.35)}
.card{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:18px 20px}
.start-here{border:1px solid rgba(62,166,255,.4);background:linear-gradient(135deg,rgba(62,166,255,.09),rgba(22,199,154,.04));border-radius:14px;padding:20px;margin:22px 0}
.legend{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0}.legend .pill{display:inline-flex;align-items:center;gap:6px}
.todo-board{display:grid;gap:18px}.todo-group>h3{margin:0 0 10px;font-size:15px}
.todo-list{display:grid;gap:10px}.todo{background:var(--panel);border:1px solid var(--border);border-left:4px solid var(--accent);border-radius:10px;padding:14px 16px}
.todo.now{border-left-color:var(--crit)}.todo.week{border-left-color:var(--high)}.todo.later{border-left-color:var(--info)}.todo.done{border-left-color:var(--ok);opacity:.86}
.todo-head{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:10px}.todo h4{margin:0;font-size:15px}.todo p{margin:7px 0}
.meta{display:flex;flex-wrap:wrap;gap:6px;margin:7px 0}.tag{display:inline-block;border:1px solid var(--border);border-radius:999px;padding:2px 8px;font-size:11px;color:var(--muted);background:var(--panel2)}
.tag.owner{color:var(--accent)}.tag.effort{color:var(--rev)}.tag.ready{color:var(--ok)}.tag.wait{color:var(--med)}.tag.gap{color:var(--crit)}
.lanes{display:grid;grid-template-columns:repeat(5,minmax(150px,1fr));gap:10px}.lane{background:var(--panel);border:1px solid var(--border);border-radius:11px;padding:14px}.lane h3{font-size:13px;margin:0 0 6px}.lane .n{font-size:24px;font-weight:750}.lane p{font-size:12.5px;color:var(--muted);margin:6px 0}
.toolbar{position:sticky;top:0;z-index:5;display:flex;flex-wrap:wrap;gap:8px;align-items:center;background:rgba(15,20,25,.96);border:1px solid var(--border);border-radius:12px;padding:10px;margin:0 0 14px;backdrop-filter:blur(8px)}
.toolbar input{flex:1;min-width:220px;background:#0b0f14;color:var(--txt);border:1px solid var(--border);border-radius:8px;padding:8px 10px}.filter{background:var(--panel2);color:var(--muted);border:1px solid var(--border);border-radius:999px;padding:6px 10px;cursor:pointer}.filter.active{color:var(--txt);border-color:var(--accent);background:rgba(62,166,255,.12)}
.scenario-list{display:grid;gap:14px}.scenario{background:var(--panel);border:1px solid var(--border);border-radius:13px;overflow:hidden}.scenario[hidden]{display:none}.scenario summary{cursor:pointer;list-style:none;padding:16px 18px}.scenario summary::-webkit-details-marker{display:none}.scenario summary:after{content:'+';float:right;color:var(--accent);font-size:20px}.scenario[open] summary:after{content:'−'}
.scenario-title{font-size:16px;font-weight:700}.scenario-sub{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}.scenario-body{border-top:1px solid var(--border);padding:16px 18px}.scenario-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.story{border-radius:10px;padding:13px 14px;background:var(--panel2);border:1px solid var(--border)}.story h4{margin:0 0 6px;font-size:13px}.story p{margin:0;color:#c7d1dc}.story.attack{border-left:3px solid var(--crit)}.story.detect{border-left:3px solid var(--accent)}.story.mitigate{border-left:3px solid var(--ok)}.story.fix{border-left:3px solid var(--high)}.story.limit{border-left:3px solid var(--muted)}
.empty{display:none;text-align:center;color:var(--muted);padding:24px;border:1px dashed var(--border);border-radius:10px}.empty.show{display:block}
.check{margin:8px 0 0;padding-left:0;list-style:none}.check li:before{content:'□';color:var(--accent);margin-right:8px}.check li.done:before{content:'✓';color:var(--ok)}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:16px}
pre{background:#0b0f14;border:1px solid var(--border);border-radius:10px;padding:14px 16px;overflow:auto;font:13px ui-monospace,Menlo,Consolas,monospace;color:#cfe8da;margin:0}
.cmd{position:relative;margin:10px 0}
.copy{position:absolute;top:8px;right:8px;font:11px ui-monospace,Menlo,Consolas,monospace;color:var(--muted);background:var(--panel2);border:1px solid var(--border);border-radius:6px;padding:3px 9px;cursor:pointer}
.copy:hover{color:var(--txt);border-color:var(--accent)}.copy.done{color:var(--ok);border-color:var(--ok)}
.flow{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:6px 0 14px}
.flow .step{background:var(--panel2);border:1px solid var(--border);border-radius:9px;padding:8px 12px;font-size:13px}.flow .arr{color:var(--accent);font-weight:700}
.note{border-left:3px solid var(--high);background:rgba(255,159,67,.06);padding:10px 14px;border-radius:0 8px 8px 0;color:#e7d3bd;font-size:13.5px;margin:10px 0}
footer{color:var(--muted);font-size:12px;border-top:1px solid var(--border);padding-top:18px;margin-top:30px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
@media(max-width:1100px){.lanes{grid-template-columns:repeat(2,1fr)}}
@media(max-width:880px){.wrap{grid-template-columns:1fr}nav{display:none}.stats,.grid2,.scenario-grid{grid-template-columns:1fr 1fr}main{padding:24px 18px}.toolbar{top:0}}
@media(max-width:560px){.stats,.grid2,.scenario-grid,.lanes{grid-template-columns:1fr}.todo-head{display:block}}
@media print{html{color-scheme:light}body{background:#fff;color:#111;font-size:11pt}.wrap{display:block;max-width:none}nav,.toolbar,.copy{display:none!important}main{max-width:none;padding:0}.card,.todo,.lane,.scenario,.story,.table-wrap{background:#fff;color:#111;border-color:#bbb;break-inside:avoid}.muted,.lane p,.story p{color:#333}a{color:#0645ad;text-decoration:underline}details:not([open])>*:not(summary),details>div{display:block!important}pre,code{background:#f5f5f5;color:#111;border-color:#bbb}}
</style></head>
<body>
<a class="sr-only" href="#report-main">Skip to report content</a>
<div class="wrap">
<nav aria-label="Report sections">
<div class="brand">Secure<span>Now</span></div>
<div class="sub"><!-- "Detection & Mitigation · Authentication" OR "Code Findings · Authentication" --></div>
<!-- one <a href="#…"> per section -->
</nav>
<main id="report-main">
<header class="top"><h1><!-- report title --></h1>
<p><code><!-- app name / domain --></code> · <span class="pill">securenow <!-- installed version --></span></p>
<p class="lead"><!-- one-sentence plain-language posture verdict --></p></header>
<div class="stats" aria-label="Report totals"><!-- 5 .stat cards; numbers MUST equal the table/finding counts --></div>
<!-- <section id="…"> blocks mirroring the Markdown sections of THIS track (5a or 5b) -->
<footer>Generated by the SecureNow authentication threat-model prompt · <!-- date --> · securenow <!-- version --> · app <code><!-- APP_KEY --></code></footer>
</main>
</div>
<script>
document.querySelectorAll('.copy').forEach(function(b){b.addEventListener('click',function(){
var pre=b.parentElement.querySelector('pre'); if(!pre)return; var t=pre.innerText;
function done(){b.textContent='Copied';b.setAttribute('aria-label','Copied to clipboard');b.classList.add('done');setTimeout(function(){b.textContent='Copy';b.setAttribute('aria-label','Copy command');b.classList.remove('done');},1500);}
function fb(){var ta=document.createElement('textarea');ta.value=t;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.focus();ta.select();try{document.execCommand('copy');}catch(e){}document.body.removeChild(ta);done();}
if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(t).then(done,fb);}else{fb();}
});});
(function(){
var input=document.querySelector('[data-scenario-search]');
var buttons=Array.from(document.querySelectorAll('[data-filter]'));
var cards=Array.from(document.querySelectorAll('.scenario'));
var empty=document.querySelector('[data-no-results]');
if(!cards.length)return;
var active='all';
function apply(){
var q=input?input.value.trim().toLowerCase():'';var shown=0;
cards.forEach(function(card){
var hay=(card.getAttribute('data-search')||card.textContent||'').toLowerCase();
var readiness=card.getAttribute('data-readiness')||'';
var priority=card.getAttribute('data-priority')||'';
var passFilter=active==='all'||(active==='do-now'&&priority==='now')||readiness===active;
var passText=!q||hay.indexOf(q)!==-1;card.hidden=!(passFilter&&passText);if(!card.hidden)shown++;
});
if(empty)empty.classList.toggle('show',shown===0);
}
if(input)input.addEventListener('input',apply);
buttons.forEach(function(btn){btn.addEventListener('click',function(){
active=btn.getAttribute('data-filter')||'all';buttons.forEach(function(x){var on=x===btn;x.classList.toggle('active',on);x.setAttribute('aria-pressed',on?'true':'false');});apply();
});});
if(location.hash){var target=document.querySelector(location.hash);if(target&&target.tagName==='DETAILS')target.open=true;}
apply();
})();
</script>
</body></html>
```
### Required reader-first HTML components
Use these structures (filled with real project evidence) rather than inventing another dense card
format. IDs are stable and cross-linked from TODOs, rules, findings, and matrices.
**TODO item** — one action, one owner, one verification path:
```html
<article class="todo now" id="todo-auth-01">
<div class="todo-head"><h4>AUTH-01 · Add a per-target reset-email cooldown</h4><span class="b high">DO NOW · HIGH</span></div>
<div class="meta"><span class="tag owner">Owner: App</span><span class="tag effort">Effort: S</span><a href="#threat-e22b">Scenario E22b</a><a href="#finding-f3">Finding F3</a></div>
<p><strong>Why:</strong> <!-- concrete risk in plain language --></p>
<p><strong>Action:</strong> <!-- exact file:line/change or link to copyable command --></p>
<ul class="check"><li>Prerequisite: <!-- … --></li><li>Verify: <!-- test + expected evidence --></li><li>Rollback: <!-- reversible step --></li></ul>
</article>
```
**SecureNow-help lanes** — summarize value and prerequisites before technical content:
```html
<div class="lanes" aria-label="How SecureNow helps">
<article class="lane"><h3>Protected now from traffic</h3><div class="n"><!-- count --></div><p><!-- what SecureNow sees + real example --></p></article>
<article class="lane"><h3>After app events</h3><div class="n"><!-- count --></div><p><!-- event prerequisite + example --></p></article>
<article class="lane"><h3>After provider data</h3><div class="n"><!-- count --></div><p><!-- adapter prerequisite + example --></p></article>
<article class="lane"><h3>External monitor needed</h3><div class="n"><!-- count --></div><p><!-- what is invisible in-band --></p></article>
<article class="lane"><h3>App/provider prevention</h3><div class="n"><!-- count --></div><p><!-- root controls SecureNow cannot replace --></p></article>
</div>
```
**Scenario toolbar + card** — the card's opening paragraph must tell the whole attack/detection/
response story even if the reader never opens SQL or the matrix:
```html
<div class="toolbar" role="search" aria-label="Filter attack scenarios">
<label class="sr-only" for="scenario-search">Search attack scenarios</label>
<input id="scenario-search" data-scenario-search type="search" placeholder="Search threats, routes, rules, or TODOs…" />
<button class="filter active" type="button" data-filter="all" aria-pressed="true">All</button>
<button class="filter" type="button" data-filter="do-now" aria-pressed="false">Do now</button>
<button class="filter" type="button" data-filter="works-now" aria-pressed="false">Works now</button>
<button class="filter" type="button" data-filter="needs-event" aria-pressed="false">Needs event</button>
<button class="filter" type="button" data-filter="needs-provider" aria-pressed="false">Needs provider</button>
<button class="filter" type="button" data-filter="gap" aria-pressed="false">Gap</button>
</div>
<div class="scenario-list">
<details class="scenario" id="threat-e22b" data-severity="high" data-coverage="partial" data-readiness="needs-event" data-priority="now" data-search="reset email bombing recipient hash distributed sources" open>
<summary><span class="scenario-title">E22b · Distributed password-reset email bombing</span>
<span class="scenario-sub"><span class="b high">HIGH</span><span class="c part">PARTIAL</span><span class="tag wait">Needs app event</span><a href="#todo-auth-01">TODO AUTH-01</a></span>
</summary>
<div class="scenario-body">
<p class="lead"><strong>In one sentence:</strong> An attacker can <!-- action + impact -->. SecureNow <!-- exact signal + decision + response -->. Your app/provider must <!-- root fix -->.</p>
<div class="flow" aria-label="Detection and response flow"><span class="step">Attacker action</span><span class="arr">→</span><span class="step">HTTP / event signal</span><span class="arr">→</span><span class="step">SecureNow rule</span><span class="arr">→</span><span class="step">Notification</span><span class="arr">→</span><span class="step">Scoped response</span><span class="arr">→</span><span class="step">Permanent fix</span></div>
<div class="scenario-grid">
<article class="story attack"><h4>Attack scenario</h4><p><!-- 2–4 plain-language sentences beginning “An attacker can…” --></p></article>
<article class="story detect"><h4>How SecureNow detects it</h4><p><!-- data source, key, threshold/window, rule, mode, notification --></p></article>
<article class="story mitigate"><h4>How SecureNow mitigates it</h4><p><!-- scoped/reversible action and automation approval --></p></article>
<article class="story fix"><h4>What you still need to do</h4><p><!-- instrumentation + root app/provider fix --></p></article>
<article class="story limit"><h4>Limits and false-positive safety</h4><p><!-- what is invisible; shared/victim safety --></p></article>
</div>
<ul class="check"><li>Definition of done: <!-- test + expected notification/control result --></li><li><a href="#rule-auth-reset-target">Open rule and commands</a></li><li><a href="#finding-f3">Open code finding</a></li></ul>
</div>
</details>
</div>
<p class="empty" data-no-results>No scenarios match this search and filter.</p>
```
The example copy is illustrative; replace it with the real routes, thresholds, event readiness,
rule names, code locations, and mitigations discovered in this project. Do not show placeholders
or invented evidence in the finished report.
**File 2 — `authentication-detection-mitigation.html`** uses the shell above with:
- `<title>`: `Detection & Mitigation — Authentication — SecureNow`
- sidebar subtitle: `Detection & Mitigation · Authentication`
- `<h1>`: `Authentication — Detection & Mitigation`
- the 15 sections of **5a**, with **every** SQL/command block wrapped in the copyable `.cmd`
pattern below.
- 5 stat cards: threats modeled · covered · partial · gaps · rules to create (numbers MUST
equal the matrix counts).
**File 4 — `authentication-code-findings.html`** uses the same shell with:
- `<title>`: `Code Findings — Authentication — SecureNow`
- sidebar subtitle: `Code Findings · Authentication`
- `<h1>`: `Authentication — Code Findings & Recommendations`
- the 11 sections of **5b**; prose may omit copy buttons, but any example/fix command is still
wrapped in `.cmd`.
- 5 stat cards: total findings · critical · high · medium · low (numbers MUST equal the
findings-table counts).
Every SQL/command block in the **Detection & Mitigation** HTML uses the copyable wrapper:
```html
<div class="cmd"><button class="copy" type="button" aria-label="Copy command">Copy</button><pre>securenow alerts rules create \
--name "..." --sql @rules/<name>.sql --apps <APP_KEY> --severity high \
--schedule "*/5 * * * *" --nlp "..."</pre></div>
```
Badge usage: severity `<span class="b crit|high|med|low">`; coverage
`<span class="c cov|part|gap">COVERED|PARTIAL|GAP</span>`; OWASP `<span class="owasp">A07</span>`;
CWE `<span class="cwe">CWE-307</span>`; mitigation
`<span class="m firewall|signature|rate|challenge|block|notify|appfix">`; rule IDs
`<span class="rid">`. Stats numbers must equal the matrix/findings row counts. The Code-Findings
HTML may omit copy buttons on prose, but still wraps any example/fix command in `.cmd`.
---
## Quality bar (the report is rejected if any of these fail)
- Every numbered and letter-suffixed catalog item is either a matrix row (detection report) / catalog entry (code
report) or an explicit N/A line — never silently dropped.
- Every matrix row has a concrete signal (threshold + window), severity, and mitigation —
no "monitor for suspicious activity" filler.
- Both HTML reports open with a plain-language posture verdict and a deduplicated prioritized TODO
board. Every TODO has one owner, priority, effort, dependency, exact action, security outcome,
verification, rollback/reversal, definition of done, and working links to its scenario/rule/
finding. TODO counts/statuses reconcile across both reports.
- Every modeled non-N/A threat has a reader-first scenario card whose first paragraph follows
"An attacker can… SecureNow sees/receives…, detects…, and alerts/contains…. Your app/provider
must…." The card separately explains attack, exact detection signal + threshold/window,
mitigation + reversal, remaining fix, prerequisite/limitation, and definition of done. Every code
finding has the equivalent attacker/detection/fix explanation.
- The five SecureNow-help lane counts reconcile with the matrix signal-source classes and clearly
distinguish protected now, needs app event, needs provider data, external monitor, and app/
provider prevention. Detect, mitigate, and permanently fix are never presented as synonyms.
- Every matrix row has exactly one signal-source class and an honest capability statement:
creatable now, creatable after app/provider instrumentation, or not currently creatable.
`PROVIDER_EVENT` is never marked covered unless verified provider telemetry is already flowing;
complete telemetry/scheduler/channel outages are never claimed as in-band detections.
- Every detection SQL keeps `__USER_APP_KEYS__` scoping (correct column per table) and selects
an `ip` column with `HAVING ip != ''`.
- When auth messaging exists, every applicable item in §3b.1 has its own detection (or an existing
rule ID), test, threshold/window, and response. The report includes both source→targets and
sources→target cardinalities, cost/quota, conversion, retry/fallback, and quota-rejection rules;
a generic per-IP OTP rule does not satisfy this bar.
- No auth-message event or report contains a raw email, phone, OTP, token, or message body; target
correlation uses a keyed/HMAC or salted stable hash and bounded attributes.
- Multi-step ATO, support recovery, post-auth security changes, evasion, provider control-plane,
out-of-band provider usage, and detection-coverage health are each modeled and tested when their
prerequisites exist. Sequence queries correlate on opaque durable IDs and still return the
triggering/current non-empty IP required by SecureNow remediation.
- The Detection report contains the complete detection-health/governance table, including owner,
signal source, baseline/threshold provenance, mode, notification channel, last validation,
false-positive budget, victim-safe runbook, and reversible response.
- **Phase 0.5 ran**: the resolved installed `securenow` version appears in BOTH reports'
appendix, and no command/flag/column or automatic event is emitted that the installed SDK/CLI
does not expose (else it is annotated `# requires securenow >= <version>`). Proposed custom
events are explicitly labeled and are used only when the installed `track()` accepts string
event types.
- Every detection rule is a **complete copyable unit** (SQL → `rules/<name>.sql` → full
`securenow alerts rules create …` → dry-run test); flags match `alerts rules --help`.
- Every 🔴 gap appears in the detection report's "Known gaps" section with an interim app fix
(linked to the code report) **and** the "contact the SecureNow team" line.
- The implementation plan runs top-to-bottom with `<APP_KEY>` substituted in and is the command-
oriented expansion of the deduplicated TODO board.
- **Four** files are written to `threat/01-authentication/` (detection-mitigation .md+.html,
code-findings .md+.html); the two tracks cross-link; both HTML files are self-contained
(inline CSS/JS, no CDN/fonts/network) and **every command block in the detection HTML has a
working Copy button**; the stats cards in each HTML match its table/finding counts.
- HTML remains understandable without JavaScript, uses semantic/keyboard-accessible controls,
wraps wide tables, keeps prose readable, works on mobile and print, and contains no unresolved
placeholders. Scenario search/filter buttons work for all six filters, deep links open the
intended card, and the no-results state is visible when appropriate.
- The split is honest: SecureNow-runnable detections/mitigations live in the Detection report;
code/config changes live in the Code-Findings report; nothing security-relevant is dropped.
- The Detection report's mitigation section presents the **full toolbox** (§3c: firewall ·
instant-block · block [global / route / method / temporary] · rate-limit [IP / route / IP+route]
· challenge · auto-block · revoke · trusted · allowlist · fp · app-fix), and **each modeled
threat's matrix row selects specific, scoped mitigation(s) from it** — never a generic "block
the IP."
- **Every false-positive-prone rule is tagged `test-first`** and carries the `--mode test` →
observe (3–7 days) → `--mode prod` promotion workflow; only high-precision rules are
`prod-ready`. The action plan creates the test-first rules in `--mode test` and has an explicit
"promote after N days" step.
- A one-line summary is printed back: per-track file paths, threat counts, rules-to-create
count, code findings by severity, gaps, resolved SDK version.
<!-- ════════════════ END OF PROMPT ════════════════ -->