security
Technical notes on web development, DevOps, and AI integration.
54 articles
- 03:53tooling
The Auditor Uses the Same Ruler as the Gate
An audit report accused eight documentation commits of missing trailers; all eight were false positives. One filter line aligned the auditor with the gate.
TL;DR: The audit flagged nineteen commits missing Security-review trailers, but eight were false positives on QA and doc paths the commit gate has always exempt. Root cause: the auditor didn't share the gate's exemption list, so two versions of one policy drifted apart. Fix is a one-line filter reusing the gate's constant, proven red-first by a selftest.
#git#bash#testing - 03:53security
The Read-Only Audit: The Missing Half of a Commit Gate
The commit gate refuses a trailer-less message in seconds, but the configuration behind it drifts silently. A read-only sweep closes that gap.
TL;DR: The commit gate enforces a Security-review trailer but can silently vanish through a lost executable bit or a moved hooksPath. A read-only audit subcommand in review_gate.sh sweeps commits, warnings, slice-gate results, and registration, always exiting 0. The gate prevents, the audit detects; together they keep the invariant honest.
#git#bash#security - 23:52database
Loyal CASCADE: When Deleting an Account Takes the Content With It
The 409 guard never fired because CASCADE removed the content first. Migration 000067 flips the order: RESTRICT refuses at the database, then the guard speaks.
TL;DR: A delete endpoint removed a citizen account plus all its content because the foreign keys used ON DELETE CASCADE, letting InnoDB wipe child rows before the app's ErrHasContent guard could check them. Migration 000067 switched those constraints to RESTRICT, MySQL's default, so the database refuses first. Five integration tests verify both up and down migrations.
#mysql#go#security - 22:45security
An Empty Scope Is Not Everything: Fail-Closed Choreography
An empty scope column used to mean ALL for legacy tokens. The four-step choreography that flipped the middleware to deny 403 BIDANG_UNSET.
TL;DR: An empty bidang scope was silently treated as ALL, a classic failing-open bug that let unscoped accounts pass authorization. Retiring it took choreography: backfill data, kill the shim's producers, prove a census of zero empty rows, then flip middleware to deny with 403 BIDANG_UNSET. Two denial layers and one documented exception (system actor userID 0) make the deny-by-default contract auditable.
#go#security#rbac - 21:24backend
When the Guard Cannot Answer: Fail-Closed Media Deletion
A failing usage census used to count as permission to delete. Now ErrCensusUnavailable cancels the delete: row and file survive, client gets 503.
TL;DR: Media deletion used to fail open: if the usage-count query errored, the code assumed the file was safe to delete. The fix returns ErrCensusUnavailable, mapped to a 503 CENSUS_UNAVAILABLE response, with real details logged server-side per OWASP guidance. Tests now verify deletion is blocked, data stays intact, and no stray files are written.
#golang#error-handling#http - 20:45testing
Coverage Percentage Is Not a Shield: Lock the Reject Arms
A Go middleware coverage audit from 27 to 96.7 percent: what httptest arm-by-arm reject-path testing teaches, from JWT to CORS.
TL;DR: A coverage audit showed middleware at 27 percent despite guarding authentication, and the untested paths were all security-critical rejections. Walking arm by arm with Go's httptest added 850 lines across seven files, pushing middleware to 96.7 percent without changing production code. Coverage stops climbing where fakes start lying, so each rejection arm now gets a named test immediately.
#golang#testing#security - 14:52tooling
Two-Tier Law in a Commit Hook at KotaPortal
A commit-hook script keeps two tiers of law: broken test-marker claims block the commit, while risky surfaces like auth paths or destructive migrations only earn a logged warning.
TL;DR: The commit script has two tiers: a test marker like "characterization" hard-blocks the commit unless an exact comment line is present, while risky surfaces such as auth code, destructive migrations, or dangerouslySetInnerHTML only log a warning. Hard-blocking everything would kill velocity, and hooks can be bypassed with --no-verify. The goal is raising the cost of carelessness, not building a wall.
#git#git-hooks#security - 14:00tooling
The Machine That Guards Review Claims in Commit Messages
A bash gate turns free-text Security-review claims into three machine-tested invariants on the commit-msg hook.
TL;DR: Review claims in commit messages are usually free text nobody checks, so one repo added a bash commit-msg gate turning them into machine-tested invariants. The script enforces exactly one Security-review: trailer, a fixed position above Co-Authored-By, and substance, matching "tests only" claims against a whitelist of changed paths. It's bypassable with --no-verify, but it cheaply catches honest mistakes.
#git#bash#security - 14:00security
Five Security Holes, Locked Instead of Fixed
A tests-only commit turns five weak authentication behaviors into a named inventory with owner-decision markers.
TL;DR: Instead of silently fixing five weak security behaviors, the author locked them as characterization tests with owner-decision markers. Findings include account enumeration via registration, unthrottled OTP verification, non-revoked JWTs, orphaned OTP rows, and in-memory rate-limiter state. Mapping first beats fixing from memory: each weakness becomes a prioritized decision ticket.
#testing#security#authentication