Repository navigation
v0.2.0 — Security hardening across the receiver, service, container, and CI/CD
[0.2.0] - 2026-09-02
A full security gap-review pass across the receiver, the generator
service, the container runtime, and CI/CD - triggered by an explicit
security audit of the whole plugin, not by any single reported issue.
Every finding below (including the ones from chatgpt-codex-connector's
automated review) was verified against a real build/container/render
before being fixed, not just read and patched.
Security
- Receiver: writes are now scoped to a payload size cap plus two
independent fixed-window rate limits - a per-IP one that only counts
failed secret checks (brute-force protection that can't be starved by
public noise sharing a proxy IP), and a global one bounding total
write volume regardless of source IP. - Generator service SSRF hardening: closed three separate gaps -
literal IP-address targets bypassing the DNS-resolution guard entirely,
every IPv6 form that embeds a plain IPv4 address (mapped, deprecated-
compatible, NAT64) plus deprecated IPv6 site-local addressing, and -
the most severe one - Chromium's own network stack fetching page
subresources (<iframe>,<img>, background images, in-page
fetch()/XHR, evenWebSocket) completely outside the guards that
only covered the top-levelgot-based fetch. Verified end-to-end
through the real/generatepipeline against a live private-network
trap target, not an isolated test harness. - Unauthenticated stack-trace disclosure: a malformed request no
longer leakserr.stackregardless ofNODE_ENV- two independent
layers (NODE_ENV=productionplus dedicated error-handling
middleware), neither relying on the other being set correctly. - Container runtime hardening:
init: true(reaps orphaned Chrome
subprocesses),read_only: trueroot filesystem with scopedtmpfs
mounts,cap_drop: ["ALL"]with no capabilities re-added (Chrome
already runs unsandboxed via--no-sandbox, so the commonly-cited
SYS_ADMINgrant would do nothing - verified empirically, not
assumed), andcpus/pids_limitbounds alongside the existing
mem_limit. - CI/CD scanning: the container-image scan now also runs weekly
against the actual published image (not a fresh rebuild, which would
silently re-patch OS packages regardless of what's really deployed),
the always-uploaded SARIF report now includes MEDIUM severity (not
just CRITICAL/HIGH), and Semgrep's own toolchain version is now
hash-locked and Dependabot-tracked instead of pinned inline with no
update path. - Dependency CVEs: bumped Semgrep's own pinned version past two
disclosed CVEs in its dependency chain (a HIGH-severity protobuf JSON-
recursion issue, a MEDIUM-severity setuptools sdist issue) - both
resolved by the newer release no longer needing the vulnerable
transitive dependency at all, not a version ceiling worked around. - Base image: trimmed unused OS packages (PostgreSQL client, the
Subversion toolchain,-devpackages) that Trivy was flagging CVEs
against despite nothing in this service ever using them - 90 findings
down to 15, confirmed viaapt-cache rdependsthat nothing else
installed depends on any of them. - Fixed a CodeQL-flagged tainted-format-string log injection in the
failed-generation log line.
Added
- A real unit test suite (
node:test, no new dependency) covering the
security-sensitive helpers inservice/lib.js, with coverage reporting
to Codecov. - Documentation restructured into
docs/(ARCHITECTURE.md,
DEPLOYMENT.md,SECURITY-CONTROLS.md) with request-flow and threat-
model diagrams, instead of one flat README. - A fourth mu-plugin,
wpcc-shared.php, holding CSS-sanitization logic
previously duplicated between the receiver and the injector - install
instructions now cover all four files.
Fixed
- A version tag could go missing from a manual
workflow_dispatchre-
publish of an existing tag. - Stale README content: a hardcoded old Puppeteer version, and a section
describing Dockerfile behavior that no longer existed. - Three SonarCloud findings that a real fix would have made worse, not
better (excess-return-count and unused-hook-parameter findings on
guard-clause validation and WordPress hook callbacks) - suppressed
with an inline justification instead of restructuring working code to
satisfy a generic linter heuristic.
Changed
- CodeRabbit's automatic PR review is now opt-in (
@coderabbitai review)
instead of running on every push. - Routine dependency updates: GitHub Actions (
checkout,setup-buildx,
login-action,metadata-action,setup-python,codecov-action,
build-push-action) bumped to their latest pinned-by-SHA versions.
Deploy
- Container image:
ghcr.io/solarssk/wp-critical-css:0.2.0(rolling
:latest,:0.2) - No database/state migration - this is a stateless generator service.
Redeploy the container and refresh the fourwordpress-mu-plugins/*.php
files inwp-content/mu-plugins/(the newwpcc-shared.phpfile must
actually be present, not just referenced by the other two).