Skip to content

Harden runner security, accessibility, and release checks#9

Merged
adewale merged 1 commit into
mainfrom
audit-remediation-2026-07-10
Jul 10, 2026
Merged

Harden runner security, accessibility, and release checks#9
adewale merged 1 commit into
mainfrom
audit-remediation-2026-07-10

Conversation

@adewale

@adewale adewale commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Summary

Harden the audited runtime, browser, accessibility, generated-asset, and release boundaries without changing the example catalog or existing routes.

The audit reproduced a Dynamic Worker containment bypass where submitted code could append directly to sys.stdout.parts and return 200,000 bytes despite the 64 KiB limit. It also found an unreleased ASGI response buffer, missing status observability for bridge-level 413s, permissive Turnstile result handling, stale browser-run races, weak dark-mode contrast, corrupt social-card acceptance, error-page canonical leakage, and dependency drift in CI.

What changed

  • Revalidate Dynamic Worker stdout after execution and independently cap/cancel the parent Fetch response stream; output-limit responses now propagate HTTP 413.
  • Release non-streaming Pyodide response buffers and cover Latin-1 headers, WebSocket close/disconnect behavior, and one-time ASGI lifespan startup.
  • Record bridge response status, apply security headers consistently, and set Cache-Control: no-store on runner POST responses.
  • Require Turnstile hostname and the fixed run-example action; retry transient CDN failures instead of caching a rejected loader promise.
  • Abort and sequence browser runs so stale responses cannot overwrite newer output; bound incoming #code= fragments before decoding.
  • Make Reset native, load Shiki only on code-bearing pages, react to live OS-theme changes, and announce search failures.
  • Strengthen focus indicators, output/search semantics, editor scrollbars, and dark Run-button contrast.
  • Decode every social-card JPEG and require 1200×630 dimensions in addition to provenance and exact-set checks.
  • Omit canonical/og:url metadata and emit noindex on error pages.
  • Enforce uv sync --locked --all-groups, add an npm lock, pin Wrangler 4.110.0, and audit high-severity Node dependencies in CI.
  • Correct About, analytics, graph, router, social-card, and contributor documentation.

Verification

  • make verify — 220 tests, 109 executable examples, browser contracts, SEO/cache lint, quality gates, Ruff, and generated-drift checks passed
  • scripts/format_examples.py --check
  • make verify-python-version VERSION=3.13
  • git diff --check
  • npm audit --audit-level=high — 0 vulnerabilities
  • Added/updated regression tests; the initial targeted run failed on the stdout mutation, Turnstile hostname/action, corrupt JPEG, error canonical, ASGI buffer-release, WebSocket-disconnect, and no-store/observability cases before their fixes
  • Manual local Worker check: sys.stdout.parts.append("X" * 200000) returned HTTP 413 with a bounded 9,527-byte HTML response

Browser coverage now exercises concurrent response ordering, native Reset, Unicode sharing, oversized fragments, transient Turnstile CDN retry and token/action propagation, pending editor CDN requests, search failure announcements, live light/dark theme changes, focus indicators, and contrast measurement.

Visual evidence

Before — dark Run control at 2.19:1 After — dark Run control at 7.87:1
Before: light text on the orange Run button After: dark text on the orange Run button

Reproduce from the corresponding revision with:

TARGET_URL=http://127.0.0.1:<port>/examples/values \
CAPTURE_SELECTOR=.runner-grid WIDTH=1200 HEIGHT=900 COLOR_SCHEME=dark \
OUTPUT=<output>.png node scripts/capture_browser_screenshot.mjs

Base: 46000c7; head: 730d0e3; viewport: 1200×900, dark color scheme. make browser-layout-test independently calculates the rendered contrast and fails below 4.5:1.

Risk

This touches shared Worker response handling, the ASGI bridge, browser runner state, and release workflows. Risk is constrained with defense-in-depth output caps, explicit status propagation, behavioral browser tests, adversarial unit tests, exact dependency locks, and a full verification pass. Pillow is added only to the development group for real JPEG decoding.

The repository still cannot prove the external Cloudflare account-level WAF/rate-limit rule is active; that remains an operator-side deployment control documented in docs/turnstile-runner-protection-spec.md.

@adewale adewale changed the title Audit remediation Harden runner security, accessibility, and release checks Jul 10, 2026
@adewale adewale merged commit 446f4dd into main Jul 10, 2026
1 check passed
@adewale adewale deleted the audit-remediation-2026-07-10 branch July 10, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant