Security

What protects a Plurion shop

The short version, before you move a shop here: the L$ of a sale never pass through Plurion, your data leaves with you the day you ask, and every figure on this page is counted from the code each time the page is built.

There is a lot here, and some of it is technical — it is written for anyone who wants to see how the thing actually works. If something on this page concerns you, ask us to explain it. That is a normal thing to want, and we can.

Counted at this build
4,239Automated tests
73Permission tests
13Shop isolation tests
794Parameterised queries

Every number here is recounted from the source when the page is built.

The money never touches Plurion.

The buyer pays your vendor and Second Life credits you. Plurion is never in the middle: there is no balance of yours for us to hold, and nothing of yours for us to lose.

Pays L$ Second Life credits
OriginYour buyer
In-worldYour vendor
DestinationYou
Never in this pathPlurion
Including our own revenue

On the free plan our 5% is one of those splits, sent by your vendor like any other — not deducted from a balance we hold. We hold no balance, not even for ourselves.

The one balance that does exist

Store credit — what a shop grants its own buyers, kept as a ledger. Movements are added, never rewritten.

Store credit is checked, debited and delivered as one movement — never charged twice, never charged without delivery. Three checks make that true, and the order is the guarantee.

Step 1

Is the buyer allowed?

Asked before anything else. A buyer you banned is stopped here — not after the money moved.

Step 2

Is it deliverable?

Stock present in a live box, product still sellable.

Step 3

Are the funds there?

And the amount is the one the server recomputed itself, not the one it was handed.

Then, once

Debit, then deliver

A double click, a network retry, two racing tabs all land on the same result: debited once.

The debit and the delivery are written together — either both, or neither.

An in-world sale is simpler still — the L$ never enter this path at all. These checks exist for the one balance that does: store credit.

Your shop is yours alone.

Every object you rez and every row you own carries your shop with it.

A copied prim is still just a prim

A vendor, a delivery box, a visitor counter registers once, receives its own secret, and signs every call it makes after that.

Thirteen separate gatekeepers: one per family of in-world object, plus one each for merchant and customer sessions. A vendor can only ever speak for itself — never for another one, and never for your shop.

No other merchant can reach your data

Every single way the system reads data carries your shop identifier inside the query. It is not a setting someone can forget to tick: it is part of how the data is asked for.

Thirteen tests do nothing but attempt to read another shop's data.

Your numbers stay yours

Nothing about what you earn is public. Where Plurion shows a merchant on its public network, it shows a rank, never an amount.

A shop that opts out is filtered on the server, before the response is built — no name, no region, no activity. Not a flag on a payload that still carries the data.

Your identity stays in Second Life.

Nobody signs in as you, because there is almost nothing to sign in with. The risk that actually costs a merchant their shop is not an exploit, it is someone convincing them to hand over a password — so here is what Plurion will never ask you for.

Plurion will never
  • email you about your account
  • ask for your password in-world

Anything that does either one is not us. That is the whole test — you do not need to understand how any of this works to apply it.

01

Plurion has no email address for you

You were never asked for one. There is no field anywhere that stores one, and nothing in the system can send one.

So anything reaching your inbox in Plurion's name did not come from Plurion — and you can check that yourself: you never gave us an address.

02

No Plurion object asks for your password

No Plurion object in Second Life has anywhere to type a password at all.

One that asks you for yours is not ours.

03

And the session itself cannot be read

Merchant and customer each have their own cookie, out of reach of the page's JavaScript. Every change additionally requires an anti-forgery token, so a request forged from another site does nothing.

An access link handed to a customer in-world is exchanged for a session and dies on first use.

If something breaks, the last six hours come back.

A window you can land anywhere inside, down to the second.

Recovery window — any second in it Continuous, not nightly
−6 h Now

Every write is recorded continuously, so a restore lands on any second in the last six hours — not on last night's snapshot, on the second before the mistake. Putting the service back onto a restored database was measured at three to six minutes in a drill run end to end.

9Documented incident procedures

A procedure that gets invented during an incident is a procedure nobody has read.

And day to day

A delivery that fails is retried eight times, over a widening interval — and it stays visible to you rather than being dropped quietly.

And you can leave.

The measure of a service you can trust is what happens on the day you decide to stop using it.

What that means concretely

Export whenever you want. Ask for deletion and, after a 30-day grace period you can cancel, every identifying detail is stripped across the system — names and avatar keys erased, messages and visitor history deleted.

Where the rest lives

Security is what protects the system. Privacy is what is kept, for how long, and what is left once you ask for it to go. Two questions, two pages — with the durations the system actually uses.

Read Privacy →

And what we can do to you.

A page that only lists what a service cannot do is telling you half the story. Here is the other half — the three things that are genuinely in our hands.

What does not stop it

A subscription that ends switches nothing off

Your shop keeps selling, keeps delivering and keeps its data. It moves to the free plan, which takes 5% of sales instead of a monthly fee. There is no cut-off, no grace countdown and nothing to rescue.

What does

A suspension is the one thing that stops a shop

In case of abuse or a security problem we suspend first and explain after — vendors stop selling, deliveries stop. It is the one situation where we act without telling you first, and the only one that genuinely switches a shop off.

And if we stop

You are told before the service ends

In any other case we tell you before ending the service, and you leave with your data. The terms say it in the same words.

Line by line, nothing summarised away.

Everything above, unabridged. Nobody has to read this — it is here so that the person who wants to check can.

A real database, not a simulation

Thirty-nine suites run against a real throwaway database, created for the run and deleted after it.

Every push, not a nightly run

The rest of the suite runs on every push. A boundary that breaks is a red build, not a discovery three weeks later.

Production dependencies are gated too

Production dependencies are audited every week and on every dependency change; a single high-severity advisory turns that check red.

31 lines·6 families·Recounted at every build·None of it is required reading

Every door into an account, and what holds each one shut.

Your password

Five failed attempts, then the account locks for fifteen minutes. The counter follows the avatar, not the address: spreading the attempt across machines does not get around it. A correct guess does not reset it either. A second limit applies per address, ten a minute. Passwords are PBKDF2-SHA-512 at 100,000 iterations — the platform ceiling — with a per-account salt.

The code sent by IM

The code is never stored in the clear, only its digest. Ten-minute life, five attempts.

Your customers’ access links

A link handed over in-world is exchanged for a session and dies on first use.

Old support links

Every link is exchanged for a session and revoked on first use. A bulk revocation exists.

Your session

Cookies are HttpOnly and Secure — no script on the page can read them. Two distinct cookies, merchant and customer, never mixed.

Requests from another site

An anti-forgery token is required on every mutation, merchant side and customer side alike: redelivery, spending credit, opening a ticket.

Being inside is not the same as being allowed. Your role, your shop and your own orders are separate walls, and each one is checked on the server.

What each team member can reach

Roles are checked per route, on the server, never by hiding a button. Only an owner or an admin can touch the team. Nobody can grant the owner role, and no one can promote or remove themselves. A removed member loses access on their next request, not at their next login. Seventy-three tests cover the role cascade and the team routes alone.

Your data, versus every other shop

Every data-access method carries the shop identifier in its query. Nine tests do nothing else, plus four on the delivery callback, plus a suite that runs against a real throwaway database. The same boundary is asserted again across the route tests — it is checked in every route, not in one place.

One customer’s order, versus another’s

Every order is bound to the customer who made it. A transaction identifier belonging to another customer of the same shop returns not found, and the listing endpoint refuses any product the caller does not own. The shop boundary and the customer boundary are two different walls.

Every in-world object signs what it sends. Here is what that signature covers.

Every message your vendors send

Every call is signed and must arrive within five minutes of its timestamp. Polls, heartbeats and syncs, harmless to repeat, stop there; every other call also carries a single-use token, refused the second time.

The contents of that message

The SHA-256 digest of the body is part of the signed chain: change one byte and the signature no longer matches.

Your registration key

Thirty-two random bytes, shown again only to the shop owner and rotatable from your settings — objects linked by touch no longer use it.

Where a redelivery actually goes

Product and recipient are read back from the transaction, never from the link: a redelivery URL rewritten with someone else’s name still delivers to the person who paid. Holding a customer’s session is not enough to redirect their delivery.

The credit ledger is the only balance in the system. These are the ways that balance is held.

A double click

Idempotency covers the whole operation, not just the debit: a double click debits once.

Paying for something that cannot ship

Deliverability is checked before the debit: stock present in a live box, product still sellable.

A buyer you banned

The ban applies before any mutation, and the money path enforces the same level.

Which shop gets credited

The credited shop is the one the terminal belongs to, resolved on the server. A shop identifier sent in the request body is never read.

The price actually charged

The server recomputes the amount from its own records — base price, sale, promo — and compares. Paying less returns an error and creates no transaction at all, rather than a sale at the wrong price; paying more sells at the right price and sends the difference back. The one tolerance is a sale's own price, honoured for three minutes after it ends — the time vendors take to learn it ended.

How far a discount can go

A fixed-amount discount is clamped to the gross price: the net can reach zero and never goes below. A discount cannot turn into a payment.

A refund on something already delivered

A redelivery that fails terminally on an already-delivered purchase does not credit the buyer back. What was actually delivered decides, not what the queue last reported.

One delivery, one copy

Two worker runs in parallel never claim the same job. The claim is atomic: the loser is handed nothing to do, rather than a second copy to send.

The layer below your shop — the service itself, which never touches an account.

Where the server is allowed to call out

The backend calls out to your in-world objects, whose address must match the shape of a Second Life region URL — an allow-list, not a block-list — and to browser push services, which must be public https addresses. Both are checked on the parsed URL, not on the string. A push to a vendor is checked again at the moment of the call, and redirects are refused: a destination that answers “go there instead” is a failed push, not a new target.

How the database is queried

Parameterised templates across the whole access layer — a value is never glued into a query string. Counted again at every build; today, 794 parameterised queries and no concatenated one.

The dashboard inside someone else’s page

Content policy, refusal to be framed, encrypted transport forced for two years, content type pinned.

Traffic floods

Capped at the edge on api.plurion.io, before it reaches the service.

Being refused is not the only thing that counts. What a refusal tells you counts too — a merchant fears having their numbers guessed as much as stolen.

Whether a name has an account here

The code request answers identically for a known and an unknown name, and the sixty-second cooldown applies to both. The response does not say which avatars exist here.

A shop that opted out of the public network

Opting out is applied on the server, before the response is built: no name, no region, no activity. Not a flag on a payload that still carries the data.

Your numbers, inside the public grid figures

Grid figures are aggregated across every shop. No per-shop number enters the payload, so none can be subtracted back out of it.

Whether another shop’s items exist

A cross-shop request returns not found with null fields — the same answer as a resource that never existed. Existence itself is not disclosed.

What an error message says

Malformed, empty and random input are refused cleanly, never with a server error. A duplicate signup answers with a conflict, not an internal failure carrying the database’s own words.

Your plan, from a public lookup

The kiosk lookup returns an identifier and a name. Plan and remaining days are not in the response to be found.

Responsible disclosure

And there is a person behind it.

Security work that gets someone threatened is security work that stops being reported. So the terms of reporting are written down in advance.

Report a vulnerability →