Navigation

Security Review

A security read asks what an attacker could do with a change. It is run on every change that crosses a trust boundary and, tree-wide, by the security sweep. The checklist of questions is the security skill's (references/owasp-top-10.md); this page is the process around it and the record of what has already been answered.

Sub-pages: server authority · cross-owner references. The app's runtime headers are the security posture, and the Azure estate's are the cost and security posture.

How it works

flowchart TD
  change["a change or a sweep unit"] --> checklist["the OWASP checklist"]
  checklist --> register{"row in the register?"}
  register -->|"yes, key files unchanged"| cite["cite the row"]
  register -->|"no, or code moved"| owner["read against its owner"]
  owner --> safe{"holds?"}
  safe -->|"yes"| record["add or widen the row"]
  safe -->|"no"| fix["fix commit + regression test"]
  fix --> primitive["one primitive per class"]
  primitive --> row["checklist row + register row"]
  record --> ledger["ledger trailer"]
  cite --> ledger
  row --> ledger

A verified boundary is written down once, here, and cited after. Re-deriving why a flow is safe costs a pass the same reading every time and finds nothing new; the register is what lets a later pass skip it. A row names the defence, the primitive that holds it and the page that explains it. A pass that finds the row's primitive or owner page changed since reads it again rather than trusting the row.

A finding is fixed with the defence the class needs, not the instance. The second place a hole of the same shape could appear is served by the same primitive, so a fix that hand-rolls a check for its one caller is a finding waiting to recur. Each class the checklist had no question for becomes a question there, and its defence goes to the skill or page that owns the subsystem (the enforcement ladder).

A risk the owning page accepts is a decision, not a finding. It is re-read only when the page's own revisit trigger fires.

Register of verified boundaries

BoundaryThe defence that holds itPrimitiveOwner
Who may call a procedureevery procedure starts from a builder naming who may reach it; public is a builder of its ownstandardAuthedProcedure, the room builders, standardRateLimitedProcedurethe trpc skill
A row describing another useronly public columns leave the server — never an email or a storage accountPublicUserColumns, getPublicUserColumnsthe drizzle skill, references/queries.md
A room action on another memberthe permission bit and the role hierarchy, and nobody moderates themselvesthe room permission builders, assertIsManageableRBAC, moderation
A moderation action on a callthe server evicts or revokes at the SFU, and every connection re-asks the room's doorevictRoomCallParticipants, updateLiveKitTrackSources, checkIsCallConnectionAdmittedmoderation, server authority
A message a member postsa member posts only a message or a poll; every line in the room's voice is the server'suserMessageTypeSchemamessaging
Rich text rendered as markupsanitized once at the Zod boundary, a table keeping only the sanitizer's own layout and a class only what the editor writes; v-html only on a body that passed it, server-written text as textsanitizedMessageSchema, sanitizeTextHtmlthe string-utils skill, references/html-sanitization.md
Data rendered by a chartevery legend entry is escaped in the one chart wrapper, whatever options a caller passesStyledApexChartdashboard data binding
Data a published dashboard carrieseach bound visual's snapshot keeps only the columns its query reads, so a chart of one column never publishes the rest of its sourceprojectDatasetToQuerydashboard data binding
An author's HTML on a public pagea webpage or email renders in a sandboxed iframe with an opaque origin; a survey's html questions pass the sanitizerSrcdocIframe, sanitizeHtmlpublishing
A spreadsheet exportthe owner's own data exports as typed; text others typed — a program's participant key values — has every formula trigger neutralizedescapeCsvCell, escapeUntrustedCsvCellprogram resource
Content naming another resource by idread only when the caller, or the content's owner, owns what it namesrequireOwnedResource, checkIsResourceAssetReadablecross-owner references
An anonymous caller's identitythe rightmost X-Forwarded-For entry, which the front end appended, with its port droppedgetIpAddressrate limiting
A bearer token or a guessable iddrawn from a cryptographic source, compared in constant time, and kept out of every log linecreateId, checkIsUploadFileTokenValidfile uploads
A log linean event is logged by its id and subject, never its data, and a token is redacted from an error before it is loggedthe Functions event handlers, the webhook proxy routethe error-handling skill, references/logging-sinks.md
A blob name built from inputevery client-supplied segment is one separator-free, non-dot segment, so no write or delete leaves its authorized prefixBLOB_SEGMENT_REGEXfile uploads
A scheduled senddelivery re-runs the same creation rules the composer does, membership included, inside the job's claimgetMessageCreationRejectionmessaging
A body larger than it claimsmeasured before it is downloaded and capped while it inflates; quota reserved under a row lockreadStagedResourceContent, readResourceContentDelta, reserveStorageBytesfile uploads, storage quotas
An anonymous writea write that adds rows spends the slow budget, and its payload is capped at the property it is stored inslowRateLimitedProcedure, surveyResponseModelSchemasurvey resource
A stale savethe version check is part of the one UPDATE that writes the rowsaveResourceContentresource save state
A query or filter built from inputSQL through Drizzle's builder or the sql tag, Table filters through clause serializationserializeClauses, escapeLikethe drizzle skill, the azure-table skill
A public read that spends a third party's quotaanswered once per process, so no caller can exhaust the server's allowance for everyonegetCommitCountserver authority
A link that configures the pageit asks the reader to Connect, warns when it points at another computer, and never acts on its ownthe agent console's linkedHost, getRemoteHostnameagent console host
A link that starts a programthe program takes the link as its one argument and refuses a launch carrying anything more, so a crafted link cannot pass flagscheckIsSchemeLaunchTamperedhost installer
An automation fed by public GitHub eventsa branch is matched with its repository, only the review bot's comments reach a session, and the session's environment is stripped of secretsthe collector's event filter, checkIsMarkedreview collector runner

Key files

Paths relative to the repo root.

FileRole
.agents/skills/security/SKILL.mdthe rules a security read follows
.agents/skills/security/references/owasp-top-10.mdthe checklist, one section per category
.agents/ledgers/security/README.mdthe tree-wide sweep's areas and find recipe

Details

Command palette

Keyboard shortcuts