SAIOS ran a 14-test abuse audit on a contact form nobody was using yet, and hand-scoped a database permission for every feature after it. Nobody asked for either. Here's what two build logs say about whether the governance SAIOS sells is something it actually does to itself first.
Somewhere in SAIOS's own build history is a security test log for a contact form that, at the time, had almost no visitors. Fourteen numbered scenarios, run directly against the live endpoint, before anyone called the form done. A SQL-injection-shaped payload. A script-tag payload. A simulated database outage. Six rapid submissions from one address, timed to see exactly when the sixth one gets refused. Nobody was attacking this form. The team tested it like something was coming anyway.
That instinct shows up twice in one week of build history — once in the contact form, once in the admin console built right after it — and neither time does it read like a rule someone enforced. It reads like a default.
What "boring" actually got
The contact form's database account can do exactly three things — read, write, update — on exactly one table. Not the database. One table. No delete. Compromise that account completely, and an attacker inherits a very short list of things they're allowed to do, because nobody granted more than the form itself needed.
Stopping abuse didn't come down to one clever trick. It stacked four unglamorous mechanisms: a hidden field a bot fills in and a human never sees; a minimum-time-to-submit check the server re-verifies itself instead of trusting the browser; a rate limit; a sixty-second window that quietly absorbs an accidental double-click instead of logging it twice. None of these is impressive alone. Together, a bot has to beat all four before a fake submission reaches the database — and the one time the team deliberately broke the database to see what a visitor would learn about it, the answer was nothing. A generic error, visible only to the visitor. The real failure, with everything an attacker would want, stayed in a log only the server can read.
The console didn't get a memo. It got the same instinct.
The admin console, built days later to manage that same form's submissions, was never handed a copy of these rules. It arrived at them again anyway. Every feature that changes or deletes something checks a security token first and never builds a database query by gluing text together — the same two habits from the contact form, just applied without anyone re-deciding them.
The contact form
- Database account limited to three verbs (read, write, update) on one table — no delete.
- Four-layer abuse mitigation: a honeypot field, a server-revalidated timing check, a rate limit, and a 60-second duplicate window.
- Requester IPs stored only as HMAC-SHA256 hashes, never raw.
The console, days later
- Every state-changing route checks a CSRF token first and never builds a query by gluing text together.
- Database grants added one feature at a time, scoped to exactly the table that feature touches — never one broad standing grant.
- Activity log records that an action happened and who performed it, never the sensitive content involved.
The clearest echo is smaller and stranger. The console keeps a running log of admin activity: who archived what, who deleted which submission, who changed their password, when. That log is explicit about what it will not keep. Delete a submission, and the log records that a submission was deleted, and by whom. It does not keep a copy of what was deleted. The evidence that something happened is preserved. The content that made the action sensitive in the first place is not — on purpose, because it never needed to be, and now it can't leak from a log nobody thought to guard as carefully as the database itself.
That's not a security feature. It's a preference, showing up somewhere nobody was watching for it.
The system that manages the site quietly started following the same rule as the site's own message to everyone else: capability isn't authority, and evidence isn't the same thing as the content behind it.
Even the database permissions grew the same way twice. Every new console feature — archiving, deleting, changing a password — got its own narrow grant, added exactly when that feature needed it and scoped to exactly the table it touched. Nobody stood up one broad admin account and reused it, even though reusing it would have been faster.
The one thing that wasn't security at all
Not everything the build logs caught was about locking something down. A design review of the console turned up a plainer problem: it rendered in generic system fonts and never used the typography the rest of the site is built around. The review's own conclusion was that this — not the color scheme, not the layout — was the main reason the console felt like a bolted-on tool instead of part of the same product as the public site. A separate pass, while building a new grid layout for the Field Notes archive, caught that reusing the site's existing article styling would have quietly put numbered bullets on every card, because both used the same HTML list markup. Fixed before it shipped. Small, unglamorous, the kind of bug that's invisible right up until it isn't.
Is this proportionate?
Here's the tension the build logs don't resolve on their own: this is, today, a low-traffic development environment. Fourteen abuse scenarios and hand-scoped database grants for a form almost nobody has used yet is either exactly right, or a lot of ceremony for not much yet at stake. The logs don't argue the case either way. They just show the standard getting applied before there was a visible reason to need it, and leave the proportionality question sitting there, unresolved, for later.
That's arguably the more interesting fact than any individual test result. An operating approach that only shows up once the stakes are obvious isn't an operating approach. It's a reaction. What two build logs from one week actually show is smaller and more specific: when nobody was going to check, the team checked anyway. Whether that holds as the surface area grows past a contact form and an admin console is the next thing worth watching — not the last.
- 01Database privilege scoping (3 verbs, 1 table, no DELETE) — SAIOS Contact Form DEV Handoff §5.
- 02Four-layer bot/abuse mitigation (honeypot, server-revalidated timing, rate limit, 60s duplicate window) — handoff §6.
- 0314-scenario live test matrix, incl. XSS/SQLi-shaped payloads stored inert and simulated DB outage returning a generic error with no internal detail — handoff §6 and §11 (table of all 14 scenarios).
- 04Requester IPs stored only as HMAC-SHA256 hashes, never raw — handoff §6.
- 01Console CSRF-token + prepared-statement discipline applied uniformly across every state-changing route — services/admin/public/index.php, commits 3ffac69 and 22b8f4a.
- 02Activity log records that a submission was deleted and by whom, never the submission's content — services/admin/src/ActivityLog.php and its call sites, commit 3ffac69.
- 03Incremental, feature-scoped DB grants added one at a time rather than one broad standing grant — db/migrations/0003_grant_admin_delete.sql and 0005_grant_console_privileges.sql.
- 01Design-review finding that generic system fonts (not color/layout) were judged the main reason the console read as a bolted-on tool — commit 02c1f0b message and sharedStyle() in services/admin/public/index.php.
- 02List-styling bug caught before shipping (shared <ol>/<li> styling would have applied numbered bullets to a new card grid) — commit 02c1f0b, app/field-notes/page.tsx and app/field-notes/[slug]/page.tsx.
- 01Proportionality question is this article's own framing, not a claim from either source — flagged here as editorial interpretation, not fact, for review.
Field Notes publish on no fixed schedule — only when there is a real perspective worth developing. The contact page has an opt-in for occasional updates, or email hello@robertsantore.com directly.