AfterPack sorts its protections into classes. Each class raises the cost of reversal differently. Knowing which class covers a region of your code tells you what an attacker recovers if they read it. The Protection Map colors every token by the class it landed in.
Static attacker, defined
These are static-attacker classes. They describe what someone who reads the bytes faces: grep, AST tooling, a deobfuscator pass, or an LLM that explains code without running it. An attacker who runs the artifact under instrumentation is a separate, stronger case, covered in the threat model.
The classes
| Class | What a static attacker recovers | Tier |
|---|---|---|
| Renamed & encoded (polynomial-injective) | The structure, with effort. Names and literals take real pattern-recognition work. That work has to be redone on every build. | Free |
| Flattened & fused (polynomial-non-injective) | An equivalent program with the same behavior. Control flow is flattened and identities are fused, so several different original computations collapse to the same output. The mapping back to which one you wrote is gone. | Free |
The Free tier reaches both classes across your entire bundle (the full matrix is in Plans & tiers). Higher presets push harder within those classes. The default preset is light (complexity target 2), so set a stronger preset explicitly for production, for example --preset=hard. At hard, the engine applies control-flow flattening, identity fusion, and constant destruction uniformly across the bundle.
No build produces it, and no region is ever classed "destroyed & fused". /* @afterpack preset=extreme */ raises a region to complexity target 80 with the string floor on, which is real, measurable protection inside the flattened & fused class.
What recovering a class gets an attacker
What a class gets an attacker depends on what they were after.
- A secret (an API key, a license threshold, a hardcoded table): neither class hides it on its own. A secret comes out of any program that behaves the way yours does, including the equivalent one recovered from a flattened-and-fused region. Protecting a secret takes a different mechanism. See Protecting a secret.
- Understanding and cloning your code: the flattened & fused class gives real protection here. The attacker gets a working, readable equivalent, but never proof of which implementation you actually shipped: no attribution, no library fingerprint, no confirmation it is the same algorithm as a specific project it may have come from. See What AfterPack does not replace for the limits of this property.
- Locating and patching one check (disabling a paywall, flipping one
return true): neither class helps much on its own. The attacker only needs to find that one node. Finding it again costs something, and it resets on every release. The anti-tamper transform (transforms.selfIntegrity.enabled) makes a patched build produce garbage instead of running. See Best practices on rotation.
Verify it on your own build
The Protection Map shows the per-token proof: your original source, colored by which class hit each line, with the transform stack behind it on hover. Open the live demo or generate your own with npx afterpack@latest.
Next
- Threat model: the adversary ladder these classes are scoped against.
- Protection Map: the per-token view for your own build.
- Best practices: what to mark and why.
- Directives: the markers that move a region between classes.
- Presets: the ladder and the complexity target each rung sets.