Skip to content
← All posts
· Delta1 Labs LicensingSecurityGuide

How to Stop License Key Sharing and Piracy

How to stop license key sharing and prevent license piracy: node-locking, activation limits, seat and device caps, re-validation and revocation.

Every vendor who sells license keys eventually finds one of theirs in the wild. Mine was a support forum: a customer had pasted their key into a public thread asking for help, and by the time I saw it, three strangers had “thanked” the post. The key was doing exactly what a naive key does — unlocking the software anywhere it was typed, as many times as anyone liked. That’s not a piracy ring; it’s ordinary key sharing, and it’s the leak that costs most vendors the most revenue. The good news is it’s also the most preventable.

This post is a practical, honest guide to stopping license key sharing: the controls that work, how they layer, and — because I’d rather you trust me than oversell you — a clear statement of what protection genuinely can and can’t do.

Key takeaway: You stop key sharing by binding each key to something finite (a machine, a seat count, an activation limit), making shared copies visible through online re-validation, and keeping a kill switch (revocation) for the ones that leak anyway. You cannot make sharing impossible — the check runs on the user’s hardware — but you can make casual sharing fail reliably and make serious cracking cost more than it’s worth.

First, understand what a bare key can’t do

The trap is the homegrown key string: generate a random-looking key, have the app accept anything matching the pattern, and email it on purchase. It feels like protection, but it has two fatal properties. First, anything the app can validate by shape, an attacker can reproduce — decompile the check and it becomes a keygen (I walk through why in how to license your software). Second, and more relevant here: a bare key carries no notion of how many installs it should permit, so nothing stops one key unlocking a thousand machines. Key sharing isn’t a bug in that model; it’s the default behaviour.

Fixing sharing starts with making the key mean something finite. That’s what the next four controls do.

Control 1 — Node-locking

Node-locking binds a license to a specific machine via a fingerprint derived from stable hardware and OS attributes. Activate a key on one machine and it’s recorded against that fingerprint; copy the same key to a second machine and the fingerprint won’t match, so the license simply doesn’t apply there. This is the single most effective control against casual sharing, because “email the key to a colleague” now just… doesn’t work for them.

The one thing to get right is tolerance. Fingerprint too strictly and an honest customer who swaps a network card or upgrades a disk gets locked out and files an angry ticket. A good implementation allows a small amount of drift so ordinary hardware changes don’t trip the lock, while wholesale changes still read as a different machine. I covered the fingerprinting mechanics and the swap-tolerance problem in depth in node-locking and seat management — rather than repeat it here, read that for the how; this post is about how node-locking fits the anti-sharing picture.

Control 2 — Activation limits and seat caps

Node-locking stops a key running on another machine simultaneously, but on its own it doesn’t stop someone activating on a rotating series of machines, or a team quietly exceeding what they paid for. That’s what seat caps and activation limits are for.

  • A seat count is the promise “this license runs on N machines at once.” It’s enforced by a server that records each activation and refuses the N+1th, returning a seat-limit result and no lease — there’s no client-side counter to patch.
  • An activation limit caps how many times a key may be activated over its life, which catches the “reinstall on a new machine every week” pattern that a live seat count alone might miss.

The crucial companion feature is self-service deactivation. The day after you ship seat caps, an honest customer retires a laptop, buys a new one, and can’t activate because all their seats are held by machines they no longer use. If moving a seat means emailing support, every hardware refresh becomes a ticket — and worse, it makes your legitimate customers feel like the enemy. Let them release a seat themselves, from a portal or an in-app “deactivate this device” button, and the cap stays enforced without punishing honest users.

Control 3 — Online re-validation

Node-locking and seat caps are enforced at activation time, but usage continues long after. Online re-validation is what keeps enforcement alive: the client periodically checks back with the server — typically by refreshing a short-lived signed lease — so the server’s view of who’s using a key stays current.

This is what makes a shared key visible. If a key you sold as a single seat suddenly shows activations from a dozen machines across three countries, re-validation is how you know, and the lease refresh is where you can act. Crucially, you do this without making legitimate users suffer through outages: because the client caches a valid lease, a brief network blip is covered by a grace window — the software keeps working offline until the lease nears expiry, then reconciles. You get ongoing enforcement and offline resilience, instead of choosing between them. The full offline-first pattern is in offline license validation explained.

Control 4 — Revocation, the kill switch

Sometimes a key leaks despite everything — it’s posted on a forum, or it belongs to a customer who charged back. You need to be able to kill that specific key, and that’s revocation.

  • Online, a revoked key drops to the unlicensed state on its next re-validation. Because leases are short-lived, “next refresh” comes around on its own, so the forum-posted key stops working for everyone using it without you lifting a finger after the click.
  • Offline, you distribute a signed revocation list with an app update — a list of dead key ids, itself signed so the client can trust it — and even disconnected clients reject known-bad keys. Slower (it moves at the speed of your releases), but it means an air-gapped install isn’t defenceless against a leaked key.

Revocation is what turns a leaked key from a permanent loss into a temporary, recoverable problem.

The honest part: what you can’t do

Now the truth I promised. You cannot make license key sharing or piracy impossible. Every control above ultimately runs, in part, on hardware the user controls, and anything that runs on a machine someone owns can — with enough skill, time and motivation — be observed, understood, and patched out. A determined attacker with a decompiler and a debugger can neutralise a client-side check. That’s not a flaw in your implementation; it’s a property of the universe you’re operating in.

So the goal is not zero piracy. The goal is economics: make casual and opportunistic sharing (the vast majority of your losses) fail reliably and cheaply, and make serious cracking cost more effort than a legitimate license is worth at your price point. That’s an achievable, honest target, and the controls here hit it. Two things sharpen it further:

  1. Keep the real enforcement on the server. Seat counting and revocation happen on infrastructure the attacker doesn’t control, so even a patched client can’t grant itself extra seats or un-revoke a dead key. The client check is a fast gate; the server is where the rules are real.
  2. Make the client hard to patch. Pair your licensing checks with obfuscation so the “just patch it out” attack costs real effort. I wrote a focused guide on this — protecting your .NET licensing checks — because a licensing system and the obfuscation guarding it are two halves of one job.

Doing this with Keyright

Keyright gives you every control above as one system: node-locking with swap tolerance, server-enforced seat caps, self-service deactivation so honest users move seats without a ticket, online re-validation with an offline grace window, and one-click revocation that reaches both online clients (on their next refresh) and offline builds (via a signed revocation list). Signing keys are isolated per tenant and the private half never leaves the server, so a leaked public key is useless for forgery. The SDKs for .NET, Node, Python and Java fail closed by design — every failure path lands in the unlicensed state, never an accidental unlock.

The free plan is enough to wire real seat enforcement and revocation end to end before you pay anything — start free, or read the .NET integration guide for the exact activation and revocation calls. And because Keyright is Nebula-compatible, it pairs naturally with obfuscated .NET builds so the client half is genuinely hard to patch.

Try Nebula.NET

Harden your .NET code in minutes — start with the free edition.