Changelog¶
All notable changes to Kagura are documented in this file.
The format follows Keep a Changelog, and the project adheres to Semantic Versioning.
[Unreleased]¶
[0.4.0] — 2026-11-04¶
Added¶
- Rewritten paper with explicit threat model and implementation boundaries, reproducible selected-pass measurements, and a separate historical shipped-profile deployment experiment. Generated tables and raw observations distinguish code growth, bounded correctness checks and startup failures.
- Evaluation-tool regression checks across the Python CI matrix. Reports mark running, failed and completed measurements; table generation rejects incomplete reports and follows the recorded seed list.
kagurasource compiler driver for LLVM 17–22, included in default builds and release bundles. Supports explicit toolchains, separate compilation, runtime discovery and policy preflight through native check-only validation.- Opt-in
-kagura-string-scoped/"string": {"scoped": true}for XOR/AES: eligible nonthrowing, readonly, noncapturing consumers use per-call stack plaintext with a volatile wipe. Unsupported uses retain persistent storage. - MCP/CLI scoped-string policy generation and validation; doctor reports compiler-driver discovery and toolchain readiness.
-
Windows AntiDebug runtime entry points, loaded-module symbol resolution for DLL-import call indirection, and clean/patched API/IAT runtime tests.
-
Local
kagura-mcpstdio server with environment diagnosis, registry/profile discovery, policy generation and validation, paginated audit inspection, and structured baseline/obfuscated binary comparison. File inputs are scoped to a configured workspace; the tools do not write or build application artifacts. - LLVM-independent
kagura-cli.py config-checkwith policy names, types, numeric ranges and flavor validation. The MCP SDK is not needed by this CLI.
Fixed¶
- Failed paper-evaluation reruns no longer leave earlier results available as the current measurement; table generation also removes stale output on error.
- Paper descriptions distinguish Windows limitations at the historical measurement revision from runtime support added subsequently in PR #79.
- Windows debugger PEB access supports MSVC intrinsics; AntiDebug omits POSIX ptrace startup on Windows. Hardware detection uses a real CPU trap context.
- Preserve selected MSVC CRT linkage across split driver stages; safely scoped Windows pooled COMDAT literals can now be transformed.
- Ordinary COFF external calls retain linker resolution instead of attempting unexported symbol lookup.
- Strict native policy validation rejects invalid types/ranges and unused malformed flavors, including file/JSON errors; check-only mode writes no IR.
-
Correct plaintext-lifetime claims: default XOR/AES buffers remain persistent; scoped wiping is conditional and cannot erase consumer copies or registers.
-
Generate CLI policies from the same profiles and pass registry as the plugin, including current opt-in passes. Emit
allowlist/denylist,tuning.seedandpasses.dwarfin their supported locations. Report audit, symbol-map and build-ID options as additional compiler flags instead of ignored JSON keys.
Known limitations¶
- The paper records startup aborts with shipped anti-debug profiles on its arm64 macOS host. A v0.4.0 pre-release check with two additional seeds reproduced those aborts; explicit anti-debug ablations passed bounded correctness checks. This release documents the issue without changing the runtime detector. Validate profile startup on each deployment target.
[0.3.0] — 2026-10-26¶
A repair release. Several documented flags did nothing at all; a few produced binaries that could not link or crashed the compiler. In every case the reason it went unnoticed was a hole in the test suite, so the suite was rebuilt too.
October IR safety follow-up¶
- Fix string-split initialization for PHI operands by inserting it in incoming predecessor blocks (#57, #60).
- Add opt-in
-kagura-string-aggressive/"string": {"aggressive": true}for short/format strings and static aggregate references, with startup decryption and documented exclusions (#58, #59). Conservative collection remains the default. XOR runs before AES when both are enabled. - Preserve string GEP offsets, escaped pointer lifetime and pointer identity; validate complete use graphs and synchronize concurrent lazy initialization. Default AES plaintext now persists for the literal lifetime instead of using per-use stack buffers (#59).
- Repair flattening dominance/EH handling, typed local/global encryption, encrypted lookup integer widths, musttail block boundaries, frame-sensitive function splitting, VM eligibility, MSVC descriptors and debug scope identity (#61–#69).
- Validate JNI hooks before mutation (#70), preserve indirect call prototypes and support early constructors (#71), and correct typed pointer authentication access rewriting and guarded hardware initialization (#72).
- Audit all 36 registered passes. The combined LLVM 21/macOS run passes 84
CTest tests, eight differential subjects and 3,456 verifier/serialization
checks. Add a reusable cross-pass runner and a per-pass report with coverage
limits in
tests/audit/README.md(#73).
⚠️ Read this before upgrading¶
Passes that previously did nothing now do something. If you build with any of the flags below, expect your output to change — larger binaries, longer compile times, and possibly newly-exposed problems in code that was never actually obfuscated before. Re-measure size and performance before shipping.
| Flag | Behaviour before | Behaviour now |
|---|---|---|
-kagura-config=<file> |
ignored entirely | selects passes as documented |
-kagura-co |
no-op at every seed | replaces constants with MBA expressions |
-kagura-autoselect |
no-op | narrows protection per function by risk score |
-kagura-lt, -kagura-fsplit |
crashed clang | apply their transforms |
opt -passes=kagura-{bbs,bbr,dci,ibr,lt,fsplit,bbcheck,telemetry,pe,elt,mvo} |
silently inert | apply their transforms |
"profile": "FAST" \| "BALANCED" \| "STRONG" |
sv, anti-debug and (BALANCED/STRONG) tamper were left off |
enabled, matching the shipped integration/profiles/*.json |
The -kagura-config change is the largest. A policy file requesting
"profile": "STRONG" previously enabled no passes; it now enables around
fourteen.
Profiles now require kagura_runtime to be linked. All three enable
anti-debug. The shipped integration/profiles/*.json always did; the compiled
preset behind a bare {"profile": "…"} did not, and the two are now one
definition. If you select a profile without linking the runtime you will get
undefined symbols at link time where you previously got a silently weaker
binary.
integration/profiles/*.json are generated. Edit
lib/Transforms/Profiles.def and run scripts/ci/gen-profiles.py. "seed": 0
is no longer emitted — it was the default anyway, and it made
KaguraProfile.cmake pass -kagura-seed=0 on every profile build, which pinned
the seed against any later -kagura-config.
Removed: KAGURA_LEGACY_PM and the legacy pass-manager shims. They required
LLVM ≤ 16; the project requires 17.
Precedence is also now defined, where before it was undefined: an explicit
command-line flag beats the config file, so
-kagura-config=p.json -kagura-str=false disables string encryption rather
than having the profile preset silently overwrite it.
Symbol filter lists merge instead of replacing. "allowlist",
"denylist" and "protect" in a policy file used to overwrite
-kagura-allow / -kagura-deny / -kagura-protect outright, which both
contradicted that precedence rule and re-obfuscated the symbols the user had
just excluded on the command line. The result is now the union of the two
sources. If you were relying on the JSON winning, move the entries you want
into the JSON — the flag no longer disappears. "audit_out" is a scalar and
follows the ordinary rule: -kagura-audit-out on the command line now wins.
A policy file with a key the loader does not understand now says so.
"anti-debug": false (hyphen) matched nothing and was dropped in silence, so
every hand-written example in the docs — including one that told SDK vendors
how to build a non-aborting binary — quietly did the opposite of what it said.
Hyphens and underscores are now interchangeable on read, and any remaining
unrecognised key is reported by name. Add -kagura-config-strict to fail the
build instead of warning. Expect new warnings on existing policy files; each
one is a setting that was never taking effect.
Fixed¶
Features that did not work¶
-kagura-configwas a complete no-op.ConfigLoaderran as a pipeline pass, mutating theopt::flags at pipeline run time, whilePlugin.cppreads those same flags at pipeline construction time to decide which passes to add. The policy file therefore always arrived after the decision it was meant to inform. The loader now runs before the pipeline is built.-kagura-conever obfuscated a constant, at any seed. Every MBA identity is built from aConstantIntoperand, and the defaultIRBuilder<>carries aConstantFolderthat evaluated(V ^ R) ^ Rstraight back toV— so the pass stored the value that was already there. Now usesIRBuilder<NoFolder>.-kagura-vmproduced binaries that hung before their first line of output. The interpreter was fine; the pass emitted bytecode that did not mean anything.virtualize()handled binops, icmp, br, ret, load, store and three casts — PHI nodes, calls, GEPs, allocas, selects and switches all fell through to "emit NOP and carry on", and an operand it could not materialise made itcontinueout of the middle of an instruction.canVirtualize()accepted those functions regardless, so at-O1every function with a loop became bytecode that computed nothing: the loop condition degenerated to a literal 0 and the VM took the same edge forever.
Measured across the test subjects with inlining disabled, all 16 cases where the old pass virtualized anything hung, segfaulted or aborted; the 10 that appeared to pass had virtualized nothing at all.
The pass is now all-or-nothing: any shape it cannot express leaves the
function untouched. PHIs lower to stack-based parallel copies, allocas to
arena offsets, calls through a relocation pool. Two further defects fixed
along the way — the bytecode blob was a mutable global decrypted in place,
so a second call to a virtualized function re-encrypted it; and the
trampoline kept the attributes inferred from the original body, advertising
memory(none) while calling the interpreter.
Verified: output identical to an unobfuscated build for every subject at
-O0/-O1/-O2, across three PRNG seeds, on LLVM 21 and 22 — and repeated calls
into the same virtualized function now return the same result.
integration_vm_correctness guards it, and was confirmed to fail against the
old code.
-kagura-ltand-kagura-fsplitcrashed clang. Both emitted IR that fails LLVM's verifier: PHI nodes left ungrouped at the top of a block, and values erased while still in use (the freed slots were recycled, so surviving operands pointed at unrelated values of unrelated types).FunctionSplitnow threads live-out values through allocas.- Eleven passes were inert under
opt -passes=. Each re-checked its own-kagura-*enable flag inside the pass body, but that flag is only set by the-fpass-pluginentry point. Whether a pass runs is now decided once, when the pipeline is built. -kagura-autoselectwas dead three ways over: never injected into the pipeline, wrote metadata nothing read, and emitted only force-enable annotations, which merely restate the default for a pass already in the pipeline.-kagura-anti-debug,-kagura-bbcheckand-kagura-telemetrycould not link —kagura_check_tracer_pidexisted only under#ifdef __linux__while being emitted unconditionally, andkagura_bb_checkandkagura_telemetry_eventwere never defined at all.-kagura-str-aescould not link on Windows.core/blob_integrity.cneeds only<stdint.h>yet sat in theif(NOT WIN32)source group.KAGURA_UNITY_BUILD=ONdid not compile —hasOnlyGuardableUseswas defined identically in two files that share a unity group.- Four JSON policy keys —
cse_break,string_split,bbcheck,elt— were accepted and silently ignored. The key table is now generated fromPassRegistry.def.
Correctness¶
- Two
APIntwidth overflows in key generation, which aborted on anyi8/i16alloca or global. - A
VMObfuscationregister-map overflow. With assertions enabled it aborted; with them compiled out — which is what ships — it kept handing out increasing indices, so the emitted bytecode addressed past the end ofVMState::regs[]and corrupted adjacent interpreter state at run time. SymbolVisibilityset hidden visibility oninternalfunctions, which LLVM rejects (local linkage requires default visibility) and which achieves nothing anyway. It now hides unkept exported definitions.- Nine runtime checks were silently disabled.
device_attest.c,integrity_report.candplay_integrity.cdeclared symbols__attribute__((weak))under names that do not exist, then null-tested them — sokagura_appattest_local_check()always returned 1 andcollect_violation_flags()always returned 0. kagura_soft_response_checkwas exported with two incompatible signatures (POSIX vs Windows), so no portable caller could exist.kagura_tamper_detectedlived in an iOS source file, so Android and Windows links that pulledelf_integrity.obut notjailbreak_detection.ogot an undefined symbol. Both callback names now live incore/tamper_response.c.- On Darwin,
extern+weakdoes not produce a weak-undefined reference, socrash_symbolication.c's three__kagura_sym_*declarations were hard undefined symbols — breaking any consumer that force-loads the archive. - Frida port detection was trapped inside
#ifdef __linux__, i.e. absent on the platforms Frida is most used against.
Build and packaging¶
- SwiftPM could not build: all 40 source paths still referenced the
pre-reorganization flat
runtime/layout.Package.swiftis now at the repository root, where SwiftPM requires it. - Bazel built an empty library:
glob(["../../runtime/*.c"])matches nothing, and Bazel rejects uplevel references. A rootBUILD.bazeldeclares the runtime from a package that actually contains it. - CocoaPods pulled Android and Windows sources into an iOS pod — all eight
exclude_filesentries were stale — and pointed at a plugin path that does not exist. paper/*.texandrefs.bibwere gitignored and untracked, so the source behind the README's Zenodo DOI existed on one machine only.
Added¶
- Link smoke tests — 30 of them, generated from
PassRegistry.def, each compiling and linking a real executable. No test had ever linked one, which is how three passes shipped referencing undefined symbols. - The lit suite now runs. Its harness had four stacked faults and CI never
installed
lit, so 29 tests were skipped with aSTATUSmessage while the build stayed green. CI now installslitand fails if the suite is not registered. - An assertions-enabled CI job. Every other job builds
Release, soassert()is compiled out and the three assertion-firing bugs above could never have failed a CI run. - Pass tests append
verifyto every pipeline and build subjects at-O0as well as-O2, since most of what these passes get wrong involves PHI nodes, which barely exist beforemem2reg. cmake/module directory; all eightKAGURA_*options documented in one place.KAGURA_BUILD_FUZZpreviously did not exist unless tests were also enabled.install()/EXPORTrules. Release bundles were assembled by hand-copying build-tree paths; staging is nowcmake --install.integration/profiles/{fast,balanced,strong}.json— one definition of each profile, replacing five drifted copies across the integration directories.runtime/internal.h.runtime/had no headers at all; every cross-TU contract was a hand-writtenextern,kagura_on_tamper_detectedalone appearing 19 times in three inconsistent forms.include/kagura/runtime.h— the public C API of the runtime: the detectors an integrator can call, the hooks they can override, and the protected value types.docs/runtime.mdhad promised this header for some time and it did not exist, so every "Runtime hardening" sample in the cookbook failed at the#include. It also documents the trap those samples fell into: anint kagura_check_*()is a predicate, avoid kagura_*_check()runs the check and fires the tamper hook, and the two are not interchangeable. (Not yet in the install list.)-kagura-config-strict— treat an unrecognised key in a policy file as an error rather than a warning. Intended for CI: an ignored key is a silent downgrade of the shipped binary and is invisible in the build output.docs/requirements.txt, pinning the documentation toolchain.
Changed¶
CMAKE_BUILD_TYPEdefaults toRelWithDebInfo. A barecmake -B buildpreviously produced an unoptimised build with noNDEBUG, matching neither what CI tests nor what releases ship.- Duplication removed: FNV-1a (9 implementations → 1, with the constants
pinned to canonical vectors on both the pass and runtime sides),
/proc/self/mapsscanning (9 → 1),path_exists(6 → 1), dyld image scanning (5 divergent pattern lists → 1 union), module constructor priorities (7 magic integers →enum CtorPriority). runtime/CMakeLists.txtsplits sources per platform. Previously everyandroid/*.cwas compiled on macOS as an empty translation unit and everyios/*.con Linux.
Definitions that existed more than once¶
Every item here was a value or list written out in two or more places, kept in step by a comment asking the reader to remember the others.
- The strength profiles lived in four places —
applyProfile(),integration/profiles/*.json, the table indocs/configuration.mdand the prose inintegration/profiles/README.md— and had already diverged oversv/anti_debug/tamper(see above). One definition now, inlib/Transforms/Profiles.def, with a CI job that fails if the generated JSON is stale. - The VM opcode table was a C++ enum in
include/kagura/VM.hand 48#defines inruntime/core/vm_interpreter.c, plus four frame limits. A disagreement between the emitter and the interpreter of a wire format does not fail to compile and does not fail an IR-level test; it ships. Both sides now expandinclude/kagura/VMOpcodes.def. - The CLI flag declarations.
Options.cppgenerated its definitions fromPassRegistry.defwhileOptions.hlisted the 40 matching externs by hand, three of them twice. Numeric tuning parameters were worse: definition, extern, and the JSON-key-to-flag mapping inConfigLoader.cppwere three independent copies. All generated fromKAGURA_TUNINGrows now. - The pass source list in
lib/Transforms/CMakeLists.txtwas repeated in the unity-build section, and five files were in one copy but not the other. Both are globbed per directory now. (The groups had never taken effect anyway:UNITY_GROUPis ignored withoutUNITY_BUILD_MODE GROUP. Enabling it for real exposed amaskForWidth()defined identically in two Data/ files, now inUtils.)
Layout¶
include/kagura/Passes.hwas 400 lines whose section headings had drifted from the directory layout. One header per category underinclude/kagura/Passes/, each named for thelib/Transforms/subdirectory that implements it.Passes.hremains as the umbrella.- New
lib/Transforms/directories:ABI/(VTableProtection.cpp, which is not a CFG pass),VM/(VMObfuscation.cpp, which is not platform-specific) andSupport/for private headers.ObfuscationMetrics.cppjoins the other non-obfuscating passes inInfrastructure/. scripts/splits intocli/(tools you run on your own build),eval/(measurement) andci/(checks on this repository). Seescripts/README.md.- The install rule now lists the shipped headers instead of globbing
include/kagura/*.h, which had been publishing the LLVM pass-plugin headers to consumers who have no LLVM — and which excluded the.deffiles those headers expand, so the installedOptions.hcould not be included at all.
Documentation¶
- Every hand-written JSON example used keys the loader could not read.
"str-aes","anti-debug"and friends are spelled with underscores in the schema, and the doc examples used hyphens throughout, so none of them did anything.docs/cookbook/sdk-vendor.mdwas the worst case: it explained that an SDK must not crash on detection and then wrote"anti-debug": false, which was ignored, leaving"profile": "STRONG"'s AntiDebug on. The loader now accepts both spellings and the examples use the canonical one. docs/runtime.mdcited a header and two functions that do not exist.include/kagura/runtime.hnow exists (see Added);kagura_check_loaded_librarieswas never a symbol — the real name iskagura_suspicious_lib_loaded— andkagura_run_review_risk_checkis the shell scriptscripts/cli/review-risk-assessment.sh, not a C function. The same three names appeared across four cookbook pages.- The required-symbol matrix was wrong in most rows. It listed
kagura_anti_debug_initas required from the runtime when the pass defines it, named two AntiDebug symbols that no pass emits, credited StringEncryptionAES withkagura_zero_buf, and had no row at all for BasicBlockChecksum, Telemetry, JNIObfuscation or ObjCObfuscation. Rebuilt from the emitters inlib/Transforms/. -kagura-bbcheckwas advertised as working anti-patching. It is scaffolding: the shippedkagura_bb_checkis a weak always-passing stub, as Known issues has said since 0.2.1. It has been removed from the README threat table, downgraded indocs/security-model.md, and itsperformance.mdfigures relabelled as the cost of the call sites alone.- Six Japanese "translation coming later" stubs deleted.
docs/integration/{xcode,android,unreal,unity,cmake}.ja.mdanddocs/contributing.ja.mdwere 13-line placeholders standing in front of English originals of up to 535 lines, andmkdocs-static-i18nalready falls back to the complete English page when a.ja.mdis absent. A JA reader now gets the real page instead of a dead end.cmake.ja.mdalso carried a profile table that contradictedProfiles.def. - Four
.ja.mdpages had drifted from their English originals and were brought back into sync:passes/data.ja.mdandpass-order.ja.mdwere missing-kagura-string-splitand-kagura-cse-break,passes/before-after.ja.mdwas missing two whole sections, andindex.ja.mdwas missing the Cookbook and Security Model cards. docs/tuning.mdclaimed every flag on the page could be set from"tuning"; five can.docs/passes/{control-flow,platform}.mdfiledelt,vtpandvmunder the wrong subsystem — the same mismatchinclude/kagura/Passes.hrecords having fixed on the header side.quick-start.mdclaimed the release archive shipsinclude/kagura/*.h; it ships three files.
Known issues¶
- Dynamic JNI registration remains incomplete. Hook/IR mutation is repaired, but runtime helpers, method signatures and native function-address registration still need implementation. The IR audit does not establish working JNI registration or platform/device loader behavior.
clang -fpass-plugin=… -mllvm -kagura-…does not work below LLVM 22. Pre-existing, and it is the invocation the README leads with. clang parses-mllvmoptions before-fpass-pluginhas loaded the plugin, so the-kagura-*options are not registered yet and clang exits with "Unknown command line argument '-kagura-str'". Verified failing on LLVM 21 with both this branch's plugin andmain's; accepted on 22.
Working on every supported version: the shipped kagura-opt, or
opt --load-pass-plugin=<plugin> -kagura-… -passes=…. The test suite uses
the latter, which is why this went unnoticed — nothing exercised the
documented path. The docs now carry the caveat; picking a real fix (register
the options earlier, or make kagura-opt the documented entry point) is
still open.
- -kagura-bbcheck cannot detect binary patching. Its checksum is
computed over LLVM IR opcodes before code generation; the runtime has
machine code and no way to recompute that value, and block_id restarts at
1 in every function so it is not a unique key. kagura_bb_check is a
documented always-pass stub. Fixing this requires the pass to emit
post-codegen byte ranges instead.
- Most of the evaluation tooling still runs in no CI job.
differential-test.sh and verify-reproducible.sh are now in the matrix, but
tests/redteam/, tests/symbolic_exec/, tests/decompiler_eval/ and
tests/frida_resistance/ are not, so nothing checks that the resistance
claims in docs/security-model.md still hold. scripts/eval/battery_impact.py
is the only other one wired up.
- A policy file cannot be validated without compiling something. Unknown
keys are diagnosed now, and -kagura-config-strict makes them fatal, but
both still require a translation unit to run against. A -kagura-config-check
mode that lints the file on its own — for an editor or a pre-commit hook —
is still open (TODO D.1a).
[0.2.1] — 2026-07-31¶
Added¶
- Windows: a working way to run the passes.
-fpass-pluginis unavailable on Windows because the MSVC-targeted LLVM ships withLLVM_ENABLE_PLUGINS=OFF, and the staticKaguraObfuscator.libthe build produced there had no consumer — the documented "link it into your driver tool" had no such tool.kagura-optnow links the passes in and registers them by callinggetKaguraPluginInfo()directly, so building with-DKAGURA_BITCODE_TOOLS=ONgives Windows users an IR-level entry point. KAGURA_FORCE_STATIC_PLUGIN— selects the same static-linkage path on macOS and Linux, so the Windows build can be reproduced without a Windows machine. CI runs this configuration on Linux.
Fixed¶
- Windows CI verified nothing. With no loadable module, the entire test
suite short-circuited to a single
echo, so a green Windows job only meant the sources compiled. The suite now drives the passes throughkagura-opton that platform. - The static
KaguraObfuscatorarchive no longer links the imported LLVM targets. It never needed to resolve those symbols itself, and inheriting theirINTERFACEinclude directories as-isystemput the macOS SDK C headers ahead of libc++, breaking<cstddef>. Consumers link the components (Core,Support,Analysis,TransformUtils,Passes) instead.
[0.2.0] — 2026-06-30¶
A wide-coverage release. Two new IR passes, three platform attestation runtime stubs, a full documentation site with Japanese translations, a CI fix for Windows / MSVC compatibility, two post-build CLI utilities, and a single-source-of-truth refactor for the pass registry.
Added¶
New passes¶
-kagura-cse-break(Data) — Defeats decompiler CSE-recovery (Ghidra, IDA hex-rays, Binary Ninja MLIL) by duplicating shared SSA expressions so every user sees a fresh definition. Functionally identical, syntactically distinct — pattern-matching deobfuscators can no longer merge the expressions back into a single readable line.-kagura-string-split(Data) — Fragments long (≥16 byte) string literals across multiple smaller private globals; recombines them at runtime via a flag-guarded init stub on first access. Defeatsstrings -n <large>and contiguous-blob assumptions. Composes withkagura-str/kagura-str-aes: when both are enabled, neither plaintext nor ciphertext exists contiguously in the binary.
Platform attestation runtime stubs¶
runtime/ios/device_attest.c— C bindings for Apple DeviceCheck (iOS 11+) and App Attest (iOS 14+, A10+). Availability gates, nonce generation (arc4random_buf + clock + atomic counter mix), and a fast local pre-screen that short-circuits the async Apple round-trip when the environment is obviously bad.runtime/windows/etw_detection.c— ETW provider enumeration to detect analysis-tool registration (Cheat Engine, Procmon, Process Hacker, ScyllaHide GUIDs). Stub-only by default; enable the full TDH path with-DKAGURA_ETW_FULL=1+tdh.lib.
Android Play Integrity (runtime/android/play_integrity.c) is part of the
0.1.x history and is documented here for visibility.
Documentation site¶
- Full MkDocs site published at https://qusamulab.github.io/kagura, deployed
automatically from
mainvia.github/workflows/docs.yml. - Multi-section sidebar nav: Getting Started · Passes · Integration · Cookbook · Security Model · Configuration · Runtime · Project.
- Cookbook: four recipe pages — Banking / FinTech, Mobile game / anti-cheat, SDK / library vendor, DRM / license enforcement. Each includes a threat model, complete policy JSON, build commands, source-side annotations, runtime hardening code, verification commands, and explicit "still on you" boundary callouts.
- Security Model (
docs/security-model.md): STRIDE coverage matrix (strong / partial / out-of-scope), hard non-goals (plaintext secrets, side channels, determined adversaries), five load-bearing assumptions, self-evaluation tool matrix, recommended defense-in-depth layering. - Japanese localization (
mkdocs-static-i18n): English default at/, Japanese mirror at/ja/. 30 pages translated covering Home, Getting Started, every Passes page, Configuration, Runtime, Game Protection, Testing, Architecture, Contributing, Integration index, and per-system integration overviews. Cookbook + Security Model JA translations will follow in a subsequent release.
Tooling¶
scripts/kagura-strip.py— Post-build hygiene CLI. Zeros outLC_UUID(Mach-O) /.note.gnu.build-id(ELF) so release binaries don't leak a rebuild fingerprint. Run afterstrip.scripts/kagura-diff.py— Section / symbol / string diff between baseline and obfuscated binaries. Text, HTML report, or JSON dump. Validates that a release build hid the symbols and encrypted the strings it was supposed to.
Community & DX¶
- GitHub Issue templates (
bug,feature,pass-proposal) with required YAML fields, labels, and category dropdowns. - PR template with type-of-change checklist, test plan, and new-pass checklist.
.github/ISSUE_TEMPLATE/config.ymlsurfaces Discussions and the docs site, routing questions away from Issues.
Changed¶
refactor: table-driven pass registry—lib/Transforms/PassRegistry.defis now the single source of truth for every Kagura pass. Plugin.cpp shrinks from 378 → 197 lines; Options.cpp from 205 → 116 lines (net −250 lines). Adding a new pass is now a one-line edit in the registry table — no more synchronizing three separate if-chains across Plugin.cpp and Options.cpp.- README slimmed to hero + threats table + docs links. Detailed content migrated into the docs site.
- MkDocs nav consolidated to collapsible left-sidebar groups (Home, Getting Started, Passes, Integration, Cookbook, Security Model, Configuration, Runtime, Project) instead of 10 cluttered top tabs.
Fixed¶
- Windows CI (
fix/ci-windows-llvm-bump) —Build & Test (Windows, Clang-CL)job was failing onmainwitherror STL1000: Unexpected compiler version, expected Clang 20 or newerafter awindows-latestrunner image update. Bumped the LLVM tarball from 19.1.7 → 21.1.5 to satisfy the new MSVC STL requirement.
PR list¶
PRs merged in this release:
-
36 — chore: add MkDocs (foundation)¶
-
37 — docs(mkdocs): collapsible left-sidebar nav with subsections¶
-
38 — ci(windows): bump LLVM 19.1.7 → 21.1.5 for MSVC STL requirement¶
-
39 — chore(batch-a): community templates, post-build CLIs, docs banner¶
-
40 — docs(batch-b): security model + cookbook recipes¶
-
41 — feat(batch-e): platform attestation stubs (iOS / Windows)¶
-
42 — docs(batch-c): i18n — Japanese translations with English default¶
-
43 — feat(batch-d1): kagura-cse-break — defeat decompiler CSE recovery¶
-
44 — feat(batch-d2): kagura-string-split — fragment string literals¶
- (this PR) — refactor: table-driven pass registry + CHANGELOG for v0.2.0
[0.1.2] — 2026-05-24¶
See git log v0.1.1..v0.1.2 for details. Highlights:
- Paper link added to Citation
- Zenodo DOI badge
- Documentation polish
[0.1.1] — 2026-05-13¶
Initial public release iteration. See git log v0.1.0..v0.1.1.
[0.1.0] — 2026-05-09¶
First public release of Kagura as MIT-licensed OSS.