v0.14.0 — cross-site mutations refused; SQL rewriter retired
The PlatformKit OSS front door: one binary composing the nine-module starter.
Install
go install github.com/septagon-oss/platformkit@latestChanges
A security review of the surface added in v0.13.0 produced two changes.
Cross-origin state-changing requests are refused
The session cookie is SameSite=Lax, which stops a cross-site POST — the common attack — but "site" means registrable domain, not origin. Every sibling subdomain is same-site, so a deployment serving customer content, a preview host, or anything attacker-influenceable next to the console could forge authenticated mutations. That one attribute was also the only barrier: nothing failed if a later route accepted a mutation on GET, or if the cookie profile changed.
Unsafe methods that rely on the ambient session cookie must now be same-origin, checked via Sec-Fetch-Site with an Origin fallback. The rule is narrow on purpose:
- Safe methods pass — handlers already enforce that GET does not mutate.
- Requests presenting an
Authorizationheader pass untouched. A bearer token cannot be attached by a cross-site page, so SPAs on another host, mobile clients, CI, andcurlare unaffected by origin policy. - Everything else is a browser relying on cookies, and must be same-origin.
Verified with this binary: the console's own same-origin mutation succeeds (201), a cross-site forgery carrying the same cookie is refused (403), a same-site forgery from a sibling subdomain is refused (403), and a token client works from any origin (201).
SECURITY.md now states this posture explicitly.
The boot-path SQL rewriter is retired
It kept one SQLite spelling of each boot statement and translated it for Postgres at runtime. That is string surgery on a language with string literals and comments in it, and a probe found three defects immediately: a ? inside a comment consumed a placeholder number so real placeholders numbered past the argument count; a blanket type-name replacement corrupted any identifier merely containing the word (last_datetime became last_TIMESTAMPTZ); and appending ON CONFLICT DO NOTHING to a statement ending in a comment put the clause inside the comment, silently dropping insert-if-absent semantics with no error.
None could fire on the five statements that existed — all verified to translate correctly — but they were landmines for the sixth, and the type rewrite was already dead code. Each engine now carries its statements explicitly, matching how the rest of the project treats engines: an adapter per engine, never a translation at runtime.
Compatibility
- Go 1.26 or newer.
- Pre-1.0 — pin this version. A minor release may change public API deliberately.
- Behavior change: a browser request that changes state, carries the session cookie, and is not same-origin now receives
403. Token-authenticated clients are unaffected.
Links
| 📖 Documentation | https://septagon-oss.github.io/pk-docs/ |
| 💬 Discussions | https://github.com/septagon-oss/platformkit/discussions |
| 🔒 Security policy | https://github.com/septagon-oss/platformkit/blob/main/SECURITY.md |
| ⚖️ License | https://github.com/septagon-oss/platformkit/blob/main/LICENSE |