Skip to content
rev3rse

IP Vault

Protect the assets you ship.

IP Vault seals the models, data and content your app ships, in your own CI, and issues the key that opens them once to each licensed installation, wrapped to a key in the device’s hardware key store. A copy of your package is no longer a copy of your product.

How it works

The product

IP Vault

Some assets have to be on the device to be worth anything — a model that runs offline, a content library, an engine that has to answer in milliseconds. IP Vault ships those assets without also shipping the ability to open them. The assets travel sealed. Each installation receives the key that opens them once, from the vault service, wrapped to a key in its device’s hardware key store that cannot be exported. It never passes through your code, and nothing in the package can open them. It puts the cost of copying back where it was before AI agents made taking a protected build apart cheap (what changed).

What IP Vault supplies, and how the key reaches the deviceThe integrating application sits outside the vault. On the device, the Vault SDK and the hardware key store are IP Vault; on the server, the vault service does. Once, at first run, the SDK registers the installation with the vault service and the key is placed in the device key store. Every use after that is local: the application asks the SDK for an asset, the SDK reads the key from the key store and opens the asset in memory, with no network.the devicethe serverIP VAULT · ON DEVICEIP VAULT · SERVERApplicationVault SDKDevice key storehardware-backed, non-exportableVault service1 · registers, once2 · the key, once3 · asks for an asset4 · key, read locallyonce, at first runevery use after — offline

More than encryption at rest

Encrypting a file is the easy part. Encryption at rest that ships inside an app ships its key with it, in the code, in a resource, or worked out from both, so whoever has the package can find the key, and one find opens every copy. Sealing is where IP Vault starts. What it adds is everything that decides who gets a key, where the key can live, and for how long.

What it addsWhat that means
No key in the packageNothing in the app, its sealed files or your code can open them. A copied package, or a copy of an installed app’s data, carries nothing that does.
A key only for an install you licensedThe vault service checks the device’s hardware attestation: a genuine device with its bootloader locked and verified boot, running your app signed with your key. Play Integrity too, where you require it. Then your licence: an activation code with a device limit, or a voucher your own backend signs.
Bound to that deviceThe key arrives wrapped to a hardware key that cannot be exported, so the stored copy is useless on any other device.
Opened in memory, one use at a timeNothing opened is left on disk. With the ONNX Runtime and LiteRT adapters your app gets results and never holds the model. On Android devices that support it, the asset key itself can stay in the hardware key store and be used there; the data it opens is still in memory while in use.
Licences that endEach installation holds a lease: it works offline until the lease and a grace period run out, and renews when it can. Revoke an installation and it cannot renew.
Keys that rotateEvery release seals with fresh keys. A key taken from one version opens that version, not the next.
Tampering is refusedA sealed file that was modified does not open.
Proof from your pipelineThe plaintext never leaves your runner. A check after the build fails it if any plaintext input shipped, whole or in part, and every release, activation and revocation goes into a hash-chained audit log.

How it fits together

Three vault components, plus the application that integrates them. The integration boundary is the point: the key never crosses it.

ComponentRuns inRole
Vault packeryour CI: GitHub Actions or GitLab CI/CDSeals the assets your manifest names, on your own runner, and registers their keys with the vault service. The plaintext never leaves the runner. A check after the build fails it if any plaintext input shipped.
Vault SDKthe application bundleRegisters the installation once, receives the key, places it in the platform key store, and opens a sealed asset in memory when the application asks for one.
Vault serviceself-hosted or managedIssues the key to a registered installation — once — and can refuse, revoke or rotate it later.
The applicationthe integrating codebaseCalls the SDK and uses what comes back. It handles no key, carries no decryption code, and needs no network once the installation is registered.

The key moves once

WhenWhat happens
Once, at first runThe SDK registers the installation with the vault service over an authenticated channel, proving it runs on genuine hardware, and receives the asset key wrapped to a key held in the device’s hardware key store — the Android Keystore today, with the Secure Enclave on Apple devices in development — which cannot be exported. Only that wrapped copy is stored, it is useless on any other device, and it never passes through your code.
Every use after thatYour app asks the SDK for an asset. The SDK uses the key already in the key store, opens the asset in memory for that one operation, and returns it. No network, no per-use round trip, and nothing opened is left on disk.
When something changesThe vault service can refuse to register an installation, revoke a key it already issued, or rotate to a new one with your next release. A key never leaves the device it was issued to.

What this does not do

It does not make copying impossible, and we would not sell it as if it did. A device that is allowed to open an asset can in principle be made to give it up, and a key in a hardware key store is still a key on a device.

What it does is put the effort back. There is no key in the package and none that can be worked out from it, so the cheap attack — the one that runs offline against a free download and opens every copy at once — stops existing. A phone rooted the usual way cannot hold a key either: on Android, unlocking a phone to root it wipes the key along with everything else, and current iPhones have no public jailbreak at all. What remains is breaking into a locked, up-to-date device that holds a key, and instrumenting the application while it has an asset open.

That is rare skill and real time — the two things agents took away. It is the bar your protection was bought against in the first place, put back. The claim is not that nobody can do it. It is that doing it costs what it used to, that it can only be done on a device that registered for a key, and that the key is revoked and rotated out with your next release.

Fits well

Models, weights, datasets, maps, content libraries and licensed engines — anything whose value survives being copied and that has to be on the device to do its job. Products that can expect a network connection once, at first run. Android today, with adapters for ONNX Runtime and LiteRT and plain data for anything else; iOS is in development.

Needs design work first

Products that must work fully before any registration has happened. Desktop and web builds: IP Vault is for mobile devices, where a hardware key store is standard. Assets that have to be handed to someone else’s runtime in the clear. Unsealing inside a loop where microseconds matter.

Who it’s for

Who needs it.

You license an engine, a model or an SDK to other companies

Each licensee should run what it paid for, on the devices it paid for. Today a licensee who has the package has the engine. With IP Vault, a licensee has an activation code or your backend’s voucher, and the asset opens only on the installations it covers.

Your app runs a model on the device, and the model is the product

It has to be on the phone to work offline and answer fast, and it is the thing a competitor would copy. It ships sealed and opens in memory for the session that uses it.

You ship paid content, maps, datasets or rules inside the app

A licence has a lease. When a subscription ends and you revoke its licence, the installation can no longer renew, and the content stops opening once the lease and its offline grace run out, instead of staying as a permanent copy.

You already encrypt your assets, and the key ships with them

That is the most common way encryption fails. IP Vault keeps the key out of the package entirely: it is issued per installation, by a server you control, into hardware.

And the honest other side: if your paid value is produced on your own servers after checking the subscription, and nothing valuable ships to the device, you do not need IP Vault. Keep it on the server.

Start free

Put it in your pipeline.

IP Vault runs in the CI you already have, GitHub Actions or GitLab CI/CD, and starts on a permanent free tier.

StepWhat happens
1
Declare your assets
One file, ipvault.toml, lists each asset, where its plaintext lives (outside anything you package) and where the sealed file goes.
2
Seal and register in CI
The GitHub Action, or the same CLI in a GitLab job, seals each asset on your own runner and registers its key with the vault service. The plaintext never leaves the runner, and the key never touches disk.
3
Build and check
Your normal build packages the sealed files. A check after the build fails it if a sealed file is missing or any plaintext input shipped, whole or in part.
4
Open them in your app
The SDK activates each installation once and opens assets in memory, offline. Activation codes, or vouchers from your own backend, decide who gets a licence.

Three identities, kept apart

Your account owns the workspace and its apps.
A CI token lets one pipeline publish new versions of one app’s assets, and nothing else.
A licence is what your customer’s installation receives, once, from your activation code or voucher.

None of them is ever embedded in your app. A CI token cannot read a key, change a version you already shipped, or touch another app, and a pull request from a fork never receives one.

Self-serve signup is not open yet. The free tier opens with it, and this page will link to it then — it would rather say so than collect addresses for something that is not ready. To integrate before then, ask us about a design-partner place: talk to us.

No account yet? The free scan checks a release you already ship for models in plaintext. It needs no account and runs in the same two CI systems; the integration guide has the one step it takes.

What changed

What used to need a specialist now needs an agent.

Taking a protected build apart used to need two things that were hard to come by together: rare skill, and weeks of patience. AI agents have lowered both bars at once. Less expertise to begin, far less time to finish, and the work no longer has to be done by someone who has done it before.

Before agentsWith agents
Finding the one line that decides access, inside code built to be unreadable, was days of expert work.It is a search through machine-read output, and the expert is optional.
Rebuilding the state a protection layer needs before the app will start was a custom job every time.That state can be listed and rebuilt — and what the protection needs is often recoverable from files the protection itself ships.
Working around a protected piece of native code meant matching a hidden interface by hand.Where the protected piece is a standard runtime, the official public build drops straight in — and the product’s own code then loads and runs untouched.

Your protection did not get weaker. The attacker got cheaper, and got there sooner. A stack chosen to stop a rare specialist with weeks to spare is not the same stack once it is measured against an agent that works the same problem in an afternoon. What was sufficient then is not automatically sufficient now — and almost nobody has re-measured.

So the job is not to make your product impossible to copy. Nothing is impossible to copy. The job is to put the cost back where your protection was priced: a specialist, and weeks.

What we find

How protection gets bypassed.

We have taken this work all the way through on real, shipping products: paid value obtained on an ordinary device, with no purchase, still working after a restart. Below are the ways it happens. We describe them as patterns rather than case studies because the details belong to the companies involved — we tell them first, in private, and we do not publish their names.

01

One flag inside the app, and your engine runs for free

A paid app works out "has this person paid?" inside itself. Everything after that trusts the answer — the paywall, the menus, and the part that actually produces the paid result. Protection makes that answer expensive to reach. But nothing asks again at the moment the paid thing is handed over.

Change the answer once and the product runs its own engine, unchanged, on a phone with no purchase on it. The result stays after a restart, because by then it is just data the app saved for its owner.

How to check your own buildFollow the value that unlocks a paid feature all the way to the code that produces the paid result. Ask whether anything in between talks to a server that could say no.

02

The lock ships with its key

Models, weights, media and settings are shipped encrypted. That is the right instinct and more than most products do. The problem is one level down: the key can be worked out from the package it arrives in. Sometimes it is simply stored there. More often it is calculated from something inside the same download, by code that takes no input from outside the file.

No licence, account, token, server answer or device check takes part. When that is true, the lock buys time instead of drawing a line — and it opens offline, for anyone who downloads the product. Including the people who already pay, who do not need their licence to read it.

How to check your own buildAsk what the decryption step takes as input. If every input is inside the file you ship, the key is inside the file you ship.

03

A free account asks for the paid content, and gets it

Here the server-side checks are real, and in places exactly right. They are applied feature by feature. But the layer that hands over the actual thing — the catalogue, the media, the files — checks nothing. An account that has never paid asks for it, and gets it.

The sharpest version of this is not a missing check. It is a working one that nobody reads: the server correctly refuses, says so in its answer, and the app never looks at that part of the answer.

How to check your own buildSign in with a free account and ask for the paid content directly. Look at what comes back, not at what the app chooses to show.

04

Your backend trusts whoever asks nicely

Keys, tokens or service credentials recoverable from the build let someone call the paid API directly. Your app is never involved, so none of the checks inside it apply, and neither do your rate limits or your per-account quotas. What you sell is reachable by anyone who read the package once.

How to check your own buildPull the strings and configuration out of your own release build and ask whether any of them would let a stranger call a paid endpoint without your app in the picture.

05

Your engine runs fine without your app

The native library or model loads and answers from a plain test harness. The interface was the only thing holding it, and an interface is not a licence. For anyone who licenses an engine or an SDK to other companies, this is not a bug in a feature — it is the business, running for whoever took a copy.

How to check your own buildAsk whether your engine can be called without your interface. If someone on your team could get an answer out of it with a twenty-line harness, so can anyone who downloads the product.

06

One month buys the library forever

Paid content downloads into a cache with no expiry and no lease. A single honest subscription becomes a permanent copy the day it is cancelled, and nothing on the device ever asks whether the person is still paying.

How to check your own buildSubscribe, download, cancel, then turn off the network. Whatever still works is what one month actually buys.

07

The lifetime licence is a line in a settings file

A one-off or perpetual tier is granted once on the device and never revalidated — and by definition it has to keep working forever, with no renewal event to re-check it against. The loss per bypass is also the whole lifetime price rather than one month of it.

How to check your own buildFind where a perpetual grant is stored on the device and ask what revalidates it. If the answer is nothing, that storage is the entire control.

08

The desktop or web build gives up what mobile protects

The same asset ships unhardened in a web bundle or a desktop package, because the protection budget went where the install numbers are. Nobody attacks the platform you hardened. They take the one you did not, and the asset is identical either way.

How to check your own buildOpen the same asset on every platform you ship it to, and judge yourself by the weakest one.

09

The protection wraps the app, not the asset

The binary is hardened and the model, media or dataset sits beside it in the clear. Hardening covers the code that reads the asset rather than the asset itself, so the thing you bought protection for is not the thing the protection covers.

How to check your own buildWrite down what your hardening actually covers, then write down your crown jewels. Compare the two lists.

No two of those fail in the same place: a decision made inside the app, a key handled badly, a permission check in the wrong layer, a credential left in the build, an engine that answers to anyone, an asset the hardening never covered. What they share is not a type of bug:

In every case, the thing that decided whether to hand over paid value could be reached by the person who benefits from the answer.
Where the decision to release paid value sitsLeft: what we keep finding — both the decision and the paid value sit on the device, inside the zone the person who benefits can reach. Right: what holds — the value ships sealed on the device while the decision to permit each use sits on the server, outside that zone.WHAT WE KEEP FINDINGThe decisionPaid valuereleasesthe device — reachable by whoever benefitsWHAT HOLDSSealed valueThe decisionpermits each usethe devicethe server
The difference is not how good the lock is. It is which side of the line the decision sits on.

That is why this is not a check on your obfuscation. It is a check on a whole boundary — and it is why buying more protection from one vendor does not close it. Pattern 03 is the one worth sitting with: the check existed, worked, and gave the right answer, and it was thrown away one layer up. Nothing makes a better case for testing the whole path end to end.

If none of these is quite your product, that is not the all-clear it sounds like. Every shape on this page was one nobody had written down until someone looked at that particular product. The check does not start from a list of known shapes — it starts from the assets you name as valuable, and asks what it would take to obtain each one.

The service

IP Exposure Assessment

A fixed-scope engagement, in five steps, ending in a verdict you can act on rather than a list of warnings. The question it answers is what your product costs to copy today — and what it would cost after the changes we recommend. Scope and price are agreed before it starts, and you keep what it produces.

StepWhat happensWhat you get
1
You tell us what matters
You name the things you sell — the engine, the model, the content, the paid feature — and what would count as losing each one: copied out, run without permission, used offline, run under someone else’s signature, or shipped on as a working product.One short, checkable statement per asset. This is what makes the test repeatable next release.
2
We map how it could leave
We read your release files: what protection is there, where the paid/not-paid decision is made and who reads it, which code is yours and which is standard, where the keys are, and what still works offline.A map from each asset to every route that hands it over, and which control is supposed to stop each one.
3
We watch it run
We install your product the way a customer does and buy the subscription for real. Then we drive the paid flow and ask one question: at the moment the paid thing is handed over, is there a call that could refuse it?If the answer is yes, you get a cheap, honest "no problem found here" in days instead of weeks.
4
We try to take it
With your written permission we change your build in small, logged steps and run it on isolated machines against your test servers.Every input, file hash, change, command, device and result written down.
5
You get a verdict
One of: copied out, reused, shipped on, refused by your server, slowed down but not stopped, or protected — with the checks that prove it named.The evidence, a fix list in priority order, and a re-test once you ship the fix.

Protected

“Your server already refuses this” is a real result, not a failed job. It is what a release decision needs, and almost nobody will sell it to you. We will.

You keep the test

The check leaves written, re-runnable statements behind, so the second one is a quick re-test rather than buying the whole thing again.

Is this you?

Six questions.

Does a value calculated inside your own software decide whether paid features unlock?
Is there an engine, a model or a content library on the customer’s machine that is your actual product?
Does paid content keep working with no internet?
Do you sell a lifetime or one-off tier that has to be honoured on the device, forever?
Have you paid for hardening, obfuscation or anti-tamper — and never had the result checked independently against your own assets?
Do you license an engine or an SDK to other companies who ship it inside their products?

And the honest other side: if your paid value is produced on your own servers after checking the subscription, and nothing valuable ships to the client, you are probably fine. We will tell you that in days rather than weeks.

Who we are

rev3rse

We are a security research firm. We work on the thing that actually ships — the built app, the running service, the file on the device — with a public research record, a published disclosure policy, and a method we write down. This practice is that method pointed at one question: can the thing you sell be taken out of the thing you ship it in?

Talk to us

Protect the assets you ship.

Tell us what you sell, and what you would least like to see leave the machine it ships on — for an assessment, or a design-partner place on IP Vault. If you would rather just write to us: hello@rev3rse.dev.

Not ready for the full assessment? Ask for the short read: we look at your current release without changing or running anything, and send back one page within five working days.

Thank you — your message is on its way. We reply to everything, and usually within two working days.

Enough to start a conversation is enough. This form reaches us through a third-party mail provider that keeps message content, so please keep specific vulnerability detail out of it — for anything sensitive, write to security@rev3rse.dev instead.