Integrate in a coffee break.

Mark the one function that matters, pick how hard it should be to recover, and build. For per-language walkthroughs see Languages; for every flag and endpoint, CLI & API.

Quickstart

Protect a binary from the CLI. The pass runs server-side against your API key, so your protection IP never ships inside the artifact.

terminal
# 1. build your object as usual
clang -O2 -c app.c -o app.o

# 2. seal the marked functions (key from your dashboard)
veil protect --level seal app.o -o app.sealed.o

# 3. link exactly as before, nothing else changes
clang -O2 app.sealed.o -o app

The output is a drop-in replacement object. Your link step, your flags, your toolchain, untouched.

Mark the crown jewel

VeilCC protects the functions you point it at, a license check, an attestation routine, a proprietary kernel, and leaves everything else native. Mark them in source, or name them at build time.

C / C++
__attribute__((annotate("veil:seal")))
uint32_t check_license(const char *key) {
    /* … */
}
Rust · Swift
// Rust, export with the C ABI
#[no_mangle]
pub extern "C" fn check_license(/* … */) -> u32 { … }

// Swift
@_cdecl("check_license")
func checkLicense(/* … */) -> UInt32 { … }

No annotation in source? Pass a symbol list at build time, the sealer works on the compiled object, so it's language-agnostic.

Security levels

The same annotation, three strengths. Pick per function; hot paths are refused automatically.

obfuscate
Mixed-boolean arithmetic, control-flow flattening and decoys across the whole function, with a fresh moving-target seed every build. Zero cost on hot paths. The deterrence layer, it slows analysis, it doesn't stop an attacker who runs the code.
seal
The function ships as ciphertext (ChaCha20) and is decrypted into a W^X page only at call time, then scrubbed. A decompiler finds data, not logic. Right for cold, high-value functions.
device-bound
As seal, but the key is never in the binary, it's unwrapped at runtime by the device's secure enclave (or TPM), provisioned on first run. A copied binary cannot decrypt. The near-zero tier for extraction and off-device analysis.

GitHub Action

Two lines in your release workflow. The Action uploads the object to the Protection API, runs the passes with a per-build seed, and returns the protected artifact with a signed receipt.

.github/workflows/release.yml
- uses: veilcc/protect@v1
  with:
    level: seal                  # obfuscate | seal | device-bound
    symbols: check_license,attest_device
    api-key: ${{ secrets.VEILCC_KEY }}
# → writes the protected object + build-receipt.json

On-prem customers point api-url at their own Protection API; the object never leaves the network.

How protection runs

The passes and the sealer run server-side, so your protection IP never ships inside the artifact. The CLI, the GitHub Action and the console are thin clients of one Protection API.

request path
client (CLI · Action · console)
  └─ upload object + options  ─────────────▶  API gateway (Cloudflare Worker)
                                                  · authenticate key, enforce quota
                                                  · validate, store, meter
                                                  └─ run  ──▶  protection runner (container)
                                                                 · LLVM toolchain + veil-seal
                                                                 · seals / obfuscates, returns
  ◀───────────  protected object + signed receipt  ◀──────────┘

A Worker can't run the native toolchain itself, so protection runs in a container the Worker calls (Cloudflare Containers, or an external runner). The sealing algorithm stays in that image, never on the client.

Regulated and air-gapped teams run the identical runner on-prem and point the Action's api-url at it, so objects never leave the network.

Supported targets

Anything that lowers through LLVM. Verified end-to-end in our test suite today:

verified matrix
language   C   C++   Rust   Swift          verified in CI
os         macOS   Linux   Windows        verified in CI
arch       arm64   x86-64                 verified in CI
expected   Zig · TinyGo · Unity IL2CPP    same object path

We list a language as shipped only once the suite proves it end-to-end, not before.

What it does & doesn't

  • Defeats static analysis, sandboxed and automated AI reversing, off-device key recovery, naive patching, and cross-release crack reuse.
  • Raises a determined local attacker from minutes to measured hours or days, with a per-build cost-to-break number you can verify.
  • Does not make locally-run code mathematically unrecoverable: someone who executes your binary and dumps RAM during a call can still recover a sealed function. No pure-software scheme escapes that. For near-zero against a copy, use device-bound keys.

Security & privacy

The passes run on compiled objects, never source, and on the hosted API they run in memory with zero retention, we keep the build receipt, not your code. Regulated, air-gapped and defense teams run the identical Protection API on-prem. Only scan or protect binaries you own or are authorized to test.