Commits

The day of the nine merges: second audit wrapped up and dumps that no longer get corrupted

Nine ticket branches merged into main: SSRF protection without DNS rebinding, database dumps without silent data loss, unguessable ZIPs, POST-only downloads, and all three waves of the second security audit integrated.

The project’s big day: nine ticket branches completed by subagents in separate worktrees, reviewed and merged into main in increasing order of messiness.

The rebinding that no longer slips through

The SSRF guard validated the hostname with getaddrinfo, but httpx resolved DNS at connection time: an attacker-controlled DNS server could insert a private IP. The fix connects to the already validated IP while preserving Host and SNI, and the rebinding test went from reaching 10.0.0.5 to connecting to the public IP.

Dumps without silent data loss

esc_sql has carried an internal placeholder token since WP 4.8.3: every % in the content came through broken in the dump, and keyset pagination silently lost rows with % in the key. Canonical reversal with remove_placeholder_escape, composite primary keys paginated using OFFSET, and unique indexes only when they cover a single column. The ZIPs, meanwhile, are no longer guessable: a random suffix, temporary writing, and a rename only after a successful close — no truncated files masquerading as a valid copy.

The three waves of the second audit

The ticket for the twenty new findings was closed in three waves. On the portal: it no longer follows redirects with the HMAC headers embedded, restoring and deleting backups requires admin privileges, logging out or changing the password invalidates the tokens, the connector secret no longer ends up in the HTML, and lockout is atomic per IP+user. On the web: nginx serves the SPA with CSP from a non-root container, and backup downloads switch to POST with a native form so the browser can stream files over 2 GB.

The seam nobody saw coming

The merges left two seams: tests that intercepted httpx.post directly and, with the guard’s new seam, escaped to real DNS; and a PHP stub with an incompatible signature that blew up when the second branch was brought in. Small fixes, test suite green: 139 pytest tests, harness 18/18, build OK.

Closed with manual verification: no admin buttons for the operator, and Summary with Retry when the inventory fails.