Fresh container.
Every launch.

Every staging gets its own container pair on its own network, with outbound traffic default-denied and email blocked outright. A plugin you are testing cannot mail your customers, cannot reach your payment gateway, and cannot see another tenant on the platform.

✓ One network per staging ✓ Egress allow-list ✓ Email blocked
Isolation profile Locked
NetworkOne bridge per staging
CapabilitiesDropped, 9 retained
Privilege gainno-new-privileges
seccomp / AppArmorRuntime defaults
PID limit512 · DB 256
Memory limitHard · 768 MB
EgressAllow-list only
EmailBlocked, not optional
Lifetime72 h, extendable

The staging thinks it is production.
It just cannot act like it.

The real hazard of restoring a live site is not that a plugin turns hostile. It is that the copy behaves exactly like the original: order hooks fire, password resets go out, integrations sync. The container is built so none of that reaches the outside world — outbound traffic is denied unless the destination is on an allow-list you control, and email is refused at two independent layers no setting can lift.

Three boundaries.
None of them trusts the container.

01 · Tenancy

One network per staging

Each staging brings up its own bridge network with its own subnet, and it is torn down with the stack. The container runtime drops traffic between separate bridges, so one staging cannot reach another customer's web or database container — by name or by raw address. Only the reverse proxy is joined to each network.

wp-a → db-a  ok
wp-a → db-b  no route
wp-a → 10.100.x.x  dropped
02 · Egress

Deny by default

Outbound traffic is refused unless the destination is on the allow-list. WordPress.org and the update and licensing endpoints of the common commercial plugins are there so your updates work. Payment gateways and webhook relays are not — we show you what your own plugins ask for and you decide, per site.

ALLOW api.wordpress.org
ALLOW my.elementor.com
DENY  api.stripe.com
DENY  0.0.0.0/0
03 · Email

Refused, not configurable

WordPress mail is disabled, PHP's mail path writes to a log you can read instead of sending, and every SMTP, POP3 and IMAP port is closed — inside the container and again on the host, so a plugin opening its own socket gets nowhere. This one has no override, because the people it protects are your customers.

25 465 587 2525 closed
110 995 143 993 closed
wp_mail() → log only

We test the boundaries,
not just configure them.

A policy that has never been attacked is a guess. Each boundary below is exercised against a container that has had its own protections removed, so what is measured is the layer underneath — the one a compromised plugin cannot switch off.

Reach another tenant's database by hostname
From a staging container, resolve and connect to a second staging's database container.
refused
Reach it by raw IP instead
Same target, skipping name resolution entirely.
refused
Deliver mail with the container's own rules removed
Open SMTP, POP3 and IMAP sessions to major providers from a container with no egress rules of its own.
refused
Reach a host that is not on the allow-list
Payment and webhook endpoints, checked alongside allowed vendor endpoints to confirm the list is doing the deciding.
refused
Exhaust the host by forking
Fork until the kernel refuses, and confirm the ceiling holds and the host is unaffected.
capped
Update WordPress and a licensed plugin
The check that matters in the other direction: the lock must not stop the thing you came here to do.
works
Container hardening beyond this — dropped capabilities, no-new-privileges, memory and PID ceilings — is applied to both the web and database container.

Test the scary plugin anyway.

Worst case it burns down a container we were going to delete in 72 hours.

Start free Encryption & compliance →