Railway let strangers deploy with no account and gave them 60 minutes. Nothing stopped a thousand of those strangers from being the same cryptominer — except the abuse controls behind the button.
If you want that same instant agent-to-preview loop on machines you own, here is the hostile-user checklist: cap every preview's CPU and memory, deny all egress by default and keep SMTP closed, scan build inputs before they run, watch for mining and spam signals at runtime, rate-limit preview creation per origin, and tear down the namespace, DNS records, and certificates automatically when the clock runs out.
One rule sits above all the others: anonymous previews must never inherit deploy authority or persistent storage. Claiming a preview should promote it into a real tenant — not hand the keys to whatever the anonymous session built.
| Abuse vector | Control | Concrete starting point |
|---|---|---|
| One preview eats the node | ResourceQuota + LimitRange per preview namespace | 2 CPU / 4 GiB ceiling, 60-minute TTL |
| Preview phones home / spams / scans | Default-deny egress NetworkPolicy + DNS carve-out | Allow DNS + HTTPS to the app's deps only; block ports 25/465/587 |
| Free public URL for phishing | Restrict who can mint public domains | Anonymous previews get unguessable subdomains, never custom domains |
| Malicious build input | Scan before build, pin what runs | Reject known-miner images, secrets, and outbound curl-pipes at admission |
| Miner / spammer at runtime | Behavioral detection + kill switch | Sustained 100% CPU with no traffic, or SMTP-shaped egress, freezes the preview |
| One script mints ten thousand previews | Per-origin rate limits on creation | A handful of previews per IP/fingerprint per hour, with a burst cap |
| Preview outlives its owner | Automatic teardown of everything | Namespace, DNS, and certs deleted at expiry; no PVCs survive |
The rest of this post turns each row into something you can actually build on a Cluster API fleet.
Anonymous compute is an attack magnet — plan for it
Every platform that has ever offered compute without identity has been strip-mined for it. Sysdig's PURPLEURCHIN investigation documented a single actor stitching free trial and free-tier accounts across CI/CD platforms into a pooled cryptomining network — a practice the industry calls freejacking. Attackers chained multi-hour build steps together specifically because each step looked legitimate in isolation. Your anonymous preview endpoint is the same shape of target: free CPU, a public IP with your reputation attached, and no account to ban when it misbehaves.
The abuse is not hypothetical and not limited to mining. Render, Railway, and most free PaaS hosts block outbound SMTP (ports 25, 465, 587) on free tiers because the alternative is becoming a spam cannon within days. Free subdomains with automatic TLS are phishing kits waiting to happen — a convincing login-support hostname on your domain, with a valid certificate, costs the attacker nothing. And preview environments have a cleanup-shaped failure mode of their own: per-branch subdomains whose DNS records survive the environment become subdomain-takeover targets, where a recyclable platform IP or wildcard record hands your hostname to whoever claims the resource next.
So the design question is not "how do we launch previews fast" — Kubernetes can do that standing still. It is "what does each preview get, what can it touch, and what guarantees it dies on time." Answer those three before you ship the button.
Cap the compute: every preview gets a namespace and a ceiling
The unit of isolation is one namespace per anonymous preview, created with guardrails attached — never a shared namespace where anonymous pods mingle with real tenants. Three objects do the heavy lifting:
- A
ResourceQuotacaps the namespace aggregate (a starting point: 2 CPU requests, 4 GiB memory, a small pod count, zero persistent volume claims — more on why zero below). - A
LimitRangesets default requests and limits so a container that declares nothing still lands inside the ceiling instead of being rejected by quota enforcement or, worse, slipping through uncapped. - Pod Security
restrictedenforcement plus an admission policy (Kyverno, Gatekeeper, or native CEL admission) rejectsprivileged,hostNetwork,hostPath, and anything else that reaches outside the box.
Pick ceilings from a typical preview, not a convenient one: a small web service plus a build step, measured, with headroom — then verify the ceiling against the hostile case too. A miner will pin whatever you give it, so the ceiling is not about comfort, it is about bounding your worst-case bill per anonymous session: ceiling times 60 minutes times number of concurrent previews is a number you should be able to say out loud. Size the pool from that number, and put a hard maximum on concurrent anonymous previews fleet-wide so one viral afternoon cannot convert your whole node pool into other people's infrastructure.
Cage the network: default-deny, then carve out exactly what's needed
Kubernetes namespaces allow all traffic by default, so a namespace without a NetworkPolicy is not isolated at all. Every preview namespace gets a default-deny policy on ingress and egress, plus a narrow allow-list: DNS resolution (port 53 to the cluster DNS), the ingress controller's health checks inbound, and whatever narrow egress the previewed app genuinely needs. The reference pattern from sandbox operators is a default-deny egress backstop with a DNS carve-out, selected by label across all sandbox pods so a missing per-preview policy fails closed rather than open.
Three network decisions deserve special attention:
SMTP stays closed. Follow the Render/Railway precedent: block ports 25, 465, and 587 for anonymous previews with no exception path. There is no legitimate 60-minute anonymous use case that requires sending email, and the first spam run will burn the IP reputation your claimed tenants share.
Public domains are a privilege, not a default. Railway learned this in public: its April 2026 Guardrails added workspace policies that stop non-admins from generating public service domains or TCP proxies, precisely because every public endpoint is phishing and abuse surface. Mirror that split: anonymous previews get unguessable hostnames on a dedicated, clearly-ephemeral subdomain (one your abuse team can nuke without touching customer domains), and custom domains are available only after claim. No TCP proxies for anonymous sessions at all — raw TCP is where game-server abuse, proxy resale, and protocol smuggling live.
Rate-limit creation per origin. The cheapest attack on a preview system is not one expensive preview but ten thousand cheap ones. Cap preview creation per IP and per device fingerprint per hour, with a burst allowance for legitimate bursts (a classroom, a hackathon behind NAT) and a fleet-wide concurrent cap behind it. Creation is the endpoint to defend; once a preview exists it is already inside your quota and network cage.
Scan the build, watch the runtime
Anonymous input becomes running code on your machines, so the pipeline needs two checkpoints: admission and behavior.
At admission, scan build inputs before anything executes: reject images and Dockerfiles matching known-miner signatures, block build steps that pipe remote scripts into shells, and refuse to inject secrets or credentials into anonymous builds (there should be nothing to steal, because anonymous builds get no credentials — but enforce it rather than assuming it). Pin the build to a fixed builder image and a fixed set of buildpacks so "custom build logic" cannot smuggle a miner past the scanner. Anything the scanner cannot parse is rejected; fail closed.
At runtime, watch for the two shapes of abuse that pass static checks. Sustained near-100% CPU with negligible inbound HTTP traffic is a miner until proven otherwise — freeze the preview and flag it, because a legitimate load test would arrive through the ingress where you can see it. Outbound connection patterns that look like mail delivery, IRC, or peer-to-peer traffic hitting a deny rule repeatedly are a spammer or a botnet node — same response. These signals should feed an automatic freeze (scale the preview to zero, preserve the logs) with human review before any unfreeze, not a warning email nobody reads. Tune the thresholds against your real previews first: measure what a legitimate build-plus-smoke-test looks like, set the tripwire clearly above it, and record the false-positive rate before you tighten further.
Kill it on a timer — namespace, DNS, certificates, all of it
The 60-minute clock is the single most important abuse control, and it only works if expiry deletes everything. Deleting the namespace garbage-collects the pods, services, quotas, and policies in one motion — but three things live outside the namespace and need their own teardown:
- DNS records. If an external-DNS-style controller created per-preview records, expiry must delete them too, or stale records pointing at recycled IPs become takeover bait. Audit this with the same paranoia as the subdomain-takeover hunters: list records for expired previews and confirm zero orphans.
- Certificates. Short-lived certs are the right default for previews, and whatever cert-manager (or equivalent) issued must have its
Certificateobjects and orders cleaned up so renewal loops and rate-limit burn do not accumulate against your ACME account. - Storage. Anonymous previews get no persistent volumes —
PersistentVolumeClaims: "0"in the quota is not an optimization, it is a guarantee that nothing planted during an anonymous session (a poisoned cache, a staged payload, a claim-me incentive) survives expiry. Ephemeral container storage with a small limit is the whole disk story.
Expiry must be enforced by a controller with a requeue-based clock, not by asking the preview nicely: a finalizer-driven teardown that retries until every resource (routing, DNS, certs) confirms deletion, with alerting when teardown itself fails.
And the claim flow — the moment Railway's design gets right — is a promotion, not a handoff. Claiming creates a real tenant with its own identity, quota, and deploy authority, then redeploys the code there. The anonymous session's authority must never transfer: nothing the anonymous preview could reach (service accounts, tokens, network peers) should exist in the claimed tenant's trust domain.
Ship the loop, not the liability
Railway's no-account deploy is a glimpse of where the whole industry is going: the deploy button keeps moving earlier — from dashboard to CLI to agent tool call — and every step removes a human who used to be an implicit abuse check. An AI agent that can spin up a preview per task without signing up is exactly the workflow developers want, and exactly the workflow freejackers will rent by the thousand. The platforms that survive it will be the ones whose anonymous tier was designed by someone thinking like an attacker: capped, caged, scanned, watched, rate-limited, and dead on a timer.
That is all buildable on Kubernetes you own — namespaces, quotas, policies, and controllers are the same primitives your claimed tenants already rely on, just applied with zero trust instead of some. The work is not exotic; it is thorough.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.



