Type to search pages and rules.

Browse pages

Security

Security boundaries follow identity, resource ownership, data classification, and trust transitions across API, persistence, frontend, external services, and operations.

Markdown25 provisions

Intent#

Security boundaries follow identity, resource ownership, data classification, and trust transitions across API, persistence, frontend, external services, and operations. Authentication establishes identity. Each use case declares the permissions it needs, and the application guard authorizes from them.

Standards#

Keep backend authentication provider-neutral#

ruleguidance

Requirement A backend MUST validate issuer, audience, signature, lifetime, and required claims through OIDC and JWT Bearer.

Rationale Provider-specific login and session behavior belongs to a frontend or an extension. An unsigned token, an unvalidated decode, or a client-supplied identity header is never accepted.

litespec/quality/security#keep-backend-authentication-provider-neutral

Derive the actor from claims#

ruleguidance

Requirement Actor resolution MUST follow litespec/quality/security#use-one-current-actor-abstraction.

Rationale Actor resolution has one owner: the WebApi boundary. Request data never supplies the current actor.

litespec/quality/security#derive-the-actor-from-claims

Authorize each target resource#

ruleguidance

Requirement The application guard MUST authorize every protected operation from its use case's declared permissions, as litespec/backend/application#enforce-target-authorization-in-the-pipeline states, with endpoints adding only coarse policies.

Rationale One decision from one declaration stops operations about the same record asking different questions. An actor holds a role at a scope, a role allows permissions, and a use case needs permissions.

litespec/quality/security#authorize-each-target-resource

Restrict a protected collection in the database#

ruleguidance

Requirement A protected collection query MUST apply its authorization scope as a database predicate, before paging, rather than filter a materialized result.

Rationale A collection has no single target, so the check that litespec/quality/security#authorize-each-target-resource states has nothing to resolve against. Reading the unrestricted set already exposed the rows to the process. A page assembled from them leaks the total count even when every row is dropped. OWASP lists this as broken object level authorization.

Example A query for an organization's orders adds the organization predicate to the database query. It does not load every order and drop the ones the caller may not read.

litespec/quality/security#restrict-a-protected-collection-in-the-database

Validate at trust boundaries#

ruleguidance

Requirement A trust boundary MUST validate transport shape and file metadata before use, leaving message checks to application validators as litespec/backend/application#separate-input-validation-from-invariants states.

Rationale Message shape, required values, length, range, format, and pagination bounds are the validator checks litespec/backend/application#separate-input-validation-from-invariants names. Domain validates business invariants separately. Database content, provider responses, file contents, and generated text stay untrusted when they cross into a new output context.

litespec/quality/security#validate-at-trust-boundaries

Keep secrets out of tracked and observable data#

ruleguidance

Requirement A secret MUST NOT appear in source, logs, traces, exception messages, generated files, URLs, snapshots, container layers, or browser storage.

Rationale Platform secret stores hold the values and diagnostics redact sensitive configuration before it is emitted.

litespec/quality/security#keep-secrets-out-of-tracked-and-observable-data

Parameterize database input#

ruleguidance

Requirement An external value reaching the database MUST travel through a provider query API or a parameterized SQL parameter.

Rationale String concatenation or interpolation into raw command text makes the value part of the statement. The provider query API is Marten's under the baseline and EF Core's under its extension, and both parameterize. The reporting extension owns the reviewed raw SQL patterns.

litespec/quality/security#parameterize-database-input

Limit public error detail#

ruleguidance

Requirement A public error MUST use the error contract litespec/backend/api#return-stable-problem-details defines.

Rationale The error contract has one owner: the HTTP API rules. A stack trace, SQL, connection detail, provider body, uncontracted internal identifier, or authorization reason that reveals resource existence gives an attacker structure.

litespec/quality/security#limit-public-error-detail

Protect browser boundaries#

ruleguidance

Requirement A frontend MUST apply framework escaping, a documented Content Security Policy, secure headers, redirect validation, forgery protection, and sanitization of approved rich content.

Rationale A route guard or hidden control is presentation, so it never replaces API authorization.

litespec/quality/security#protect-browser-boundaries

Minimize sensitive data#

ruleguidance

Requirement A use case MUST collect, return, log, export, and retain only the fields its input and results declare.

Rationale A use case handling sensitive data states its classification, access, retention, deletion, and audit behavior on its page.

litespec/quality/security#minimize-sensitive-data

Keep a personal-data inventory per store#

ruleguidance

Requirement A platform holding personal data MUST keep a personal-data inventory per store naming the fields, purposes, and retention of each store.

Rationale An inventory the team can read is the map every export, erasure, and breach answer starts from.

litespec/quality/security#keep-a-personal-data-inventory-per-store

Apply erasure and export to every store#

ruleguidance

Requirement Erasure and export MUST reach every store holding personal data, with backups expiring inside the retention bound the Limit records state.

Rationale Stores include logs, search indexes, and outboxes beside the database. A request the team honors in the database but leaves in a log export answers half the duty. A backup cannot answer field by field, so it carries a retention bound instead.

litespec/quality/security#apply-erasure-and-export-to-every-store

Keep personal data out of logs#

ruleguidance

Requirement A log, trace, or diagnostic record MUST NOT carry personal data in clear.

Rationale Redaction at the sink fails once, while a field never emitted fails nowhere.

litespec/quality/security#keep-personal-data-out-of-logs

Treat an unsalted digest as personal data#

ruleguidance

Requirement An unsalted digest of personal data MUST receive the same handling as the data itself.

Rationale A digest without a salt reverses by table lookup, so it hides nothing from anyone holding the table.

litespec/quality/security#treat-an-unsalted-digest-as-personal-data

Report a breach within its deadline#

ruleguidance

Requirement A breach-notification procedure MUST name an owner and a backup person and meet the deadline the applicable Constraint record states.

Rationale A deadline nobody owns slips past the team, and an owner without a backup fails on the first absence.

litespec/quality/security#report-a-breach-within-its-deadline

Protect live data at rest#

ruleguidance

Requirement Live data at rest MUST carry encryption or an Exception record naming this rule.

Rationale Encryption is the default, and the Exception keeps the gap visible with its reason and review date.

litespec/quality/security#protect-live-data-at-rest

Bound abuse at exposed endpoints#

ruleguidance

Requirement A public, authentication, webhook, search, or upload endpoint MUST declare its limit as a Limit record with key, owner, and rejection response.

Rationale The key limits one caller, the owner monitors the limit, and the rejection response is 429 with a stable code.

litespec/quality/security#bound-abuse-at-exposed-endpoints

Keep one limit store across replicas#

ruleguidance

Requirement A deployment running more than one replica MUST hold its rate and concurrency counters in one store that every replica reads.

Rationale A per-process counter multiplies the declared limit by the replica count, so the limit a specification states is not the limit the system applies. The multiplier also changes when the deployment scales, which makes the effective limit unstated.

litespec/quality/security#keep-one-limit-store-across-replicas

Restrict cross-origin access#

ruleguidance

Requirement A cross-origin policy MUST list its allowed origins, methods, headers, and credential mode without using a wildcard origin.

Rationale Validated configuration owns the allowlist, so an unlisted origin cannot arrive by mistake. Deployment-owned origins are allowed when the allowlist shape is validated at startup.

litespec/quality/security#restrict-cross-origin-access

Record security audit events#

ruleguidance

Requirement A security audit event MUST record actor, action, target, outcome, timestamp, trace identifier, and available reason.

Rationale Audit records follow a documented retention and access policy, exclude secrets, and stay available for incident review. A consumer that activates the audit extension records the event through that extension instead. The extension states a wider field set, a classification rule, and a tamper-evidence rule.

litespec/quality/security#record-security-audit-events

Rotate production secrets#

ruleguidance

Requirement A production secret MUST have a secret-inventory entry naming its owner, storage location, and next rotation date, with revocation and recovery in a runbook.

Rationale Rotation allows overlap while clients switch. Procedures, logs, artifacts, and audit records carry no secret value, as litespec/quality/security#keep-secrets-out-of-tracked-and-observable-data states.

litespec/quality/security#rotate-production-secrets

Conventions#

Use one current actor abstraction#

conventionguidance

Default Expose one narrow current-actor accessor in WebApi that maps verified claims to typed identity, roles, and scopes.

Replacement A consumer replaces this default by recording an Exception that names this provision and states its reason, review date, and removal condition.

Rationale Application receives the actor through input that WebApi creates, or through a narrow trusted port when behavior must stay host-independent.

litespec/quality/security#use-one-current-actor-abstraction

Keep secure headers in host configuration#

conventionguidance

Default Define Content Security Policy, frame restrictions, content-type protection, referrer policy, and transport security in one host location.

Replacement A consumer replaces this default by recording an Exception that names this provision and states its reason, review date, and removal condition.

Rationale One location keeps the header set reviewable instead of spread across middleware registrations.

litespec/quality/security#keep-secure-headers-in-host-configuration

Use deny-by-default policies#

conventionguidance

Default Set a fallback policy requiring an authenticated user, and mark each public endpoint with AllowAnonymous intentionally.

Replacement A consumer replaces this default by recording an Exception that names this provision and states its reason, review date, and removal condition.

Rationale A new endpoint is then protected by default. Named role or scope policies add coarse checks while the guard retains resource authorization.

litespec/quality/security#use-deny-by-default-policies

Test the resource authorization matrix#

conventionguidance

Default Cover anonymous, invalid-token, unrelated-actor, owner, and each privileged grant for every protected operation.

Replacement A consumer replaces this default by recording an Exception that names this provision and states its reason, review date, and removal condition.

Rationale The matrix also covers disclosure behavior and the collection query predicate. A UI redirect or hidden control is not evidence.

litespec/quality/security#test-the-resource-authorization-matrix

Reference example#

This informative example demonstrates litespec/quality/security#authorize-each-target-resource and litespec/quality/security#limit-public-error-detail.

GET /api/posts/{id} for a private draft filters by both post ID and the author ID derived from claims. A different author receives the documented not-found or forbidden response without learning protected fields.

Verification#

IDMarkEvidence
litespec/quality/security#keep-backend-authentication-provider-neutralguidanceDoes the backend validate issuer, audience, signature, lifetime, and claims, and refuse identity headers?
litespec/quality/security#derive-the-actor-from-claimsguidanceDoes actor resolution follow the WebApi boundary rules this rule cites?
litespec/quality/security#authorize-each-target-resourceguidanceDoes the guard authorize every protected operation from its declared permissions?
litespec/quality/security#restrict-a-protected-collection-in-the-databaseguidanceDoes every protected collection query apply its scope as a database predicate before paging?
litespec/quality/security#validate-at-trust-boundariesguidanceDoes every trust boundary validate its shape and metadata before use?
litespec/quality/security#keep-secrets-out-of-tracked-and-observable-dataguidanceIs every secret absent from source, logs, traces, messages, files, URLs, snapshots, layers, and browser storage?
litespec/quality/security#parameterize-database-inputguidanceDoes every external value reach the database through a query API or parameter?
litespec/quality/security#limit-public-error-detailguidanceDoes every public error use the HTTP API error contract?
litespec/quality/security#protect-browser-boundariesguidanceDoes every frontend apply escaping, policy, headers, redirect validation, and forgery protection?
litespec/quality/security#minimize-sensitive-dataguidanceDoes every use case handle only the fields its input and results declare?
litespec/quality/security#keep-a-personal-data-inventory-per-storeguidanceDoes the inventory name the fields, purposes, and retention of each store?
litespec/quality/security#apply-erasure-and-export-to-every-storeguidanceDo erasure and export reach every store, with backups expiring inside their bound?
litespec/quality/security#keep-personal-data-out-of-logsguidanceIs personal data absent in clear from every log, trace, and diagnostic record?
litespec/quality/security#treat-an-unsalted-digest-as-personal-dataguidanceDoes every unsalted digest of personal data receive personal-data handling?
litespec/quality/security#report-a-breach-within-its-deadlineguidanceDoes the breach procedure name an owner, a backup person, and meet its deadline?
litespec/quality/security#protect-live-data-at-restguidanceIs every live store encrypted, or covered by an Exception naming this rule?
litespec/quality/security#bound-abuse-at-exposed-endpointsguidanceDoes every exposed endpoint declare its limit, and answer 429 above it?
litespec/quality/security#keep-one-limit-store-across-replicasguidanceDo all replicas read rate and concurrency counters from one store?
litespec/quality/security#restrict-cross-origin-accessguidanceDoes the cross-origin policy list origins, methods, headers, and credential mode without a wildcard origin?
litespec/quality/security#record-security-audit-eventsguidanceDoes every security audit event record actor, action, target, outcome, timestamp, trace, and reason?
litespec/quality/security#rotate-production-secretsguidanceDoes every production secret have a secret-inventory entry and a revocation runbook?
litespec/quality/security#use-one-current-actor-abstractionguidanceDoes WebApi expose one current-actor accessor, or does an Exception record the replacement?
litespec/quality/security#keep-secure-headers-in-host-configurationguidanceAre the secure headers defined in one host location, or is an Exception recorded?
litespec/quality/security#use-deny-by-default-policiesguidanceIs every new endpoint protected by default, or is an Exception recorded?
litespec/quality/security#test-the-resource-authorization-matrixguidanceDoes every protected operation pass each caller case the convention lists, or is an Exception recorded?