# Security acceptance (SSAT)

> Check every SSAT item with evidence before go-live or a major release.

Engineering safeguards · /ssat/ · 2026-11-02

The System Security Acceptance Test (SSAT) is Neutron's security checklist for a system.

## Ask the agent to check the SSAT

**Codex**

```text
$neutron:ssat-review Check [system or repository] against the SSAT in [SSAT file], adding the client's requirements from [client checklist, or none].
For each item, decide whether its statement applies to this system. Check every line of an applicable item using read-only access to the code, CI configuration and deployed settings.
Record evidence for each line: file and line, CI run, configuration value or command output. Then propose each item's Status: Closed, RA with the gap and its risk, or NA with the reason.
Do not change code, settings or infrastructure.
```

**Claude Code**

```text
/ssat-review Check [system or repository] against the SSAT in [SSAT file], adding the client's requirements from [client checklist, or none].
For each item, decide whether its statement applies to this system. Check every line of an applicable item using read-only access to the code, CI configuration and deployed settings.
Record evidence for each line: file and line, CI run, configuration value or command output. Then propose each item's Status: Closed, RA with the gap and its risk, or NA with the reason.
Do not change code, settings or infrastructure.
```

## Fill each row with evidence

- **SSAT-1** (high risk; checked by code review): **Every applicable SSAT line is backed by evidence.** Record a file and line, CI run, configuration value, command output or test result, not a bare "Yes". Each gap is fixed before go-live or recorded as a risk acceptance with its justification.

* Answer the item's statement in Applicability first. "No" needs one line saying why, such as "no user file uploads".
* In Remarks, give each numbered checklist line its own evidence. Check the deployed system, not the intended design: settings, CI runs and live responses beat a diagram or a ticket.
* Set the item's Status: Closed when every line holds, RA (risk acceptance) when a gap remains, or NA when the item doesn't apply.
* For RA, write in Justification what is missing, the risk, who accepted it and the ticket that will close it. A gap that is neither fixed nor accepted blocks go-live; an agent can propose RA, but only a person accepts it.
* Rerun the affected items after a significant change to sign-in, data, infrastructure or integrations.

> **Example: An SSAT line, recorded two ways**
>
> | Line                              | Remarks                                                                                          | Why                                                 |
> | --------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------- |
> | RM-001 · 5. Secret scanning in CI | 5. Yes                                                                                           | Unverifiable; the scan might exist and only report. |
> | RM-001 · 5. Secret scanning in CI | 5. The `secrets` job in the CI workflow fails a PR on any finding; run 4821 on `7d03f5b` passed. | Anyone can open the run and confirm it blocks.      |

## Check release management (RM)

- `RM-001` Read the branch rules from the repository settings, not the docs: required review and checks on `main` and `release/*`, no direct pushes, no bypass for admins.
- `RM-001` SAST, dependency scanning and secret scanning run on every PR and fail it on a serious finding. A report-only scan is a gap. Dependency changes also need the [dependency checks](/security/#r-sec-2).
- `RM-001` Confirm every PR merged since the last SSAT had a [`pr-review`](/code-review/) run and a human approval, and that the review covers this checklist's code items.

## Check personal data (DS)

- `DS-001` List every personal-data field with the reason it is collected, and remove fields without one.
- `DS-001` Confirm encryption in transit and at rest from the database and storage settings, not from a default you assume.
- `DS-001` Trigger an error with synthetic personal data, then search logs and error reports for it. It must appear redacted or not at all.
- `DS-001` Test personal-data endpoints with two accounts, as in [Access, secrets and data](/security/#test-denied-access).
- `DS-001` Record where the data and its backups are stored, including third-party processors, and compare that with the region the project requires.

## Check infrastructure and internet exposure (SS-001, SS-002)

- `SS-001` From outside the network, confirm the database and internal services can't be reached. Export the firewall or security-group rules and check that the default is deny.
- `SS-001` Record the date of the last firewall rule review; no date is a gap.
- `SS-002` Confirm every public endpoint, APIs included, sits behind the WAF and DDoS protection.
- `SS-002` Run `curl -sI https://[host]` against the web app and the API. Both responses need HSTS, X-Content-Type-Options, a CSP (with `frame-ancestors` or X-Frame-Options) and Referrer-Policy, and no server version.
- `SS-002` Rate limits are enforced in the application, as on [SMS, OTP and paid endpoints](/otp/#check-requests-before-sending).

## Check sign-in and admin access (SS-003, SS-004)

- `SS-003` Name the identity provider. Bespoke password or token handling needs a written reason.
- `SS-003` Mobile and browser apps use OAuth with PKCE; no implicit flow.
- `SS-003` With a test account, enter wrong passwords until lockout or delay starts, and record the threshold.
- `SS-003` Record the actual access and refresh token lifetimes from configuration, and test that a revoked refresh token stops working.
- `SS-003` Request two password resets, then use the first link: it must fail. Confirm reset links expire within 15 minutes and never appear in logged URLs.
- `SS-004` List the admin accounts: named people only, MFA on every one, and an audit log entry for each admin action. Record the date of the last access review.

## Check secrets and certificates (SS-005)

- `SS-005` Every secret is read from the vault or secrets manager; search the code and CI configuration for any that aren't.
- `SS-005` Record the rotation schedule and the last rotation date for each secret.
- `SS-005` Confirm a certificate-expiry alert fires at least 30 days ahead.
- `SS-005` Run `nmap --script ssl-enum-ciphers -p 443 [host]`. TLS 1.0, TLS 1.1 and SSL must be absent.

## Check APIs, input and uploads (SS-006 to SS-008)

- `SS-006` Find the one module or middleware where permissions are decided. Have the agent review it for privilege escalation, missing scope checks and access to another user's records, and test with two accounts.
- `SS-006` Sequential IDs are acceptable only when every lookup [checks the record's owner](/security/#r-sec-1). Record which applies.
- `SS-006` Force an error in staging: the response carries a generic message, with no stack trace or internal path.
- `SS-006` Plain HTTP requests to the API are rejected. Server-to-server callers are restricted by IP as well as by credential.
- `SS-007` Check validation and permissions on the server; a frontend check alone fails. Search the code for SQL built from strings and for user input passed to shell commands.
- `SS-007` Confirm CSRF protection on every state-changing request, and output encoding wherever user text is rendered.
- `SS-008` Upload a renamed file of a disallowed type and an oversized file; both must be rejected. Confirm the malware scan and that files are served only through an authorized download.

## Check testing and third parties (SS-009, SS-010)

- `SS-009` The VAPT is run by an independent, accredited vendor and covers infrastructure, the application and the API. Every finding is fixed or risk-accepted before go-live; attach the report.
- `SS-010` Keep an inventory of every third-party service: its purpose, the data it receives and how it authenticates.
- `SS-010` Block one service in staging. The system handles the failure as designed, and the alert fires.

## Check cost, payments and broadcasts (FS, CS)

- `FS-001` Check paid calls against [SMS, OTP and paid endpoints](/otp/) and idempotency against [Money and rewards](/value-abuse/#r-val-3). Record who reconciles provider invoices, and how often.
- `FS-002` Confirm no card numbers or CVVs are stored, that refunds and reversals were tested, and that each transaction has an audit trail.
- `CS-001` Confirm only authorized roles can trigger a broadcast, and compare who holds that permission in production with the project's access policy.
- `CS-001` From staging, send a test broadcast. It reaches only test contacts, uses separate credentials and sender IDs, and carries the `[UAT]` prefix.
