Skip to content

πŸ¦‹ Nika 0.56.2 β€” Security Batch

Choose a tag to compare

@github-actions github-actions released this 31 Mar 21:31

πŸ¦‹ Nika 0.56.2 β€” Security Batch

Inference as Code Β· March 31, 2026 Β· 18 commits

πŸ§ͺ Tests πŸ”§ Builtins πŸ“¦ Transforms 🌐 Providers
9,109 30 31 7+1+1

✧ infer Β· ⎈ exec Β· β˜„ fetch Β· βŠ› invoke Β· ❋ agent


12 fixes across 4 attack surfaces πŸ›‘οΈ

This is a pure security and hardening batch. No features. No refactors. Just 12 fixes that close real vulnerabilities discovered during the serve hardening sprint. SVG entity bombs, TOCTOU races, fetch overflow, serve DoS vectors β€” each one found, fixed, and tested.

The nika serve module that launched in v0.56.0 got particular attention: localhost-only binding by default, request timeouts, atomic job queue accounting, and worker lifecycle fixes. If you're running nika serve in production, this is a mandatory update.


πŸ”’ Security fixes

πŸ’£ SVG entity expansion bomb (billion laughs)

The SVG sanitizer accepted DOCTYPE declarations, which means an attacker could submit:

<!DOCTYPE svg [
  <!ENTITY a "AAAA...">
  <!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;">
  <!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;">
  <!-- ... exponential expansion -->
]>
<svg>&c;</svg>

This causes exponential memory allocation β€” the classic "billion laughs" attack. The fix: strip all DOCTYPE declarations from SVG inputs before parsing. No DOCTYPE, no entity expansion, no bomb.

⏱️ TOCTOU atomic write

nika:write had a time-of-check-to-time-of-use race:

Thread A: check if file exists β†’ no
Thread B: check if file exists β†’ no
Thread A: create file β†’ success
Thread B: create file β†’ overwrites Thread A's file

Now uses create_new (O_EXCL) for atomic file creation. If two threads race, one wins and the other gets a clean error. No silent overwrite.

πŸ”‘ Secret redaction in events

BindingDefaultApplied events could leak API keys when a with: binding used $env.API_KEY with a default() fallback. The default value appeared unredacted in trace events. Now all binding events go through the secret redactor.

🌐 Serve hardening (4 fixes)

Fix Before After
Bind address 0.0.0.0 (all interfaces) 127.0.0.1 (localhost only)
Request timeout None (infinite) 30 seconds
Job counter Non-atomic increment compare_exchange (CAS)
Counter underflow Decrement always Decrement only if successfully incremented

Warning

If you were relying on nika serve being accessible from other machines on the network, you now need to explicitly set the bind address: nika serve --bind 0.0.0.0:3000. The default changed to localhost-only for security.


πŸ› Engine fixes

5 engine fixes (expand)
  • Retry max_attempts: 0 rejected β€” AST analyzer now rejects retry: { max_attempts: 0 } at analysis time. Previously, this silently created a no-op retry that would "succeed" without executing the task. Zero retries is never intentional β€” if you don't want retry, don't add the block.

  • Duplicate task IDs in include: β€” When including partial workflows without a prefix:, duplicate task IDs between the main workflow and the included partial were silently merged. Now the analyzer catches this and reports a clear error with both task locations.

  • Fetch backoff overflow β€” Exponential backoff calculation could overflow to Infinity then wrap to 0 on very high retry counts (e.g., max_attempts: 50). Now capped at a reasonable maximum delay.

  • last(N) on strings and objects β€” The last(N) transform only worked on arrays. Now it also works on strings (last N characters) and objects (last N key-value pairs by insertion order).

  • Invoke timeout: 0 rejected β€” Like retry: { max_attempts: 0 }, a zero timeout on an invoke call is never intentional. Now rejected at runtime with a clear error.

πŸ“Š Extraction fixes

  • HTML in llm_txt extractor β€” Some sites return HTML "not found" pages at /llms.txt instead of a proper 404. The extractor now detects HTML responses and skips them instead of returning garbled markup as if it were valid llm.txt content.
  • Duplicate task IDs in include: β€” See above under engine fixes.

♻️ CI improvements

  • Windows CI matrix β€” Windows is now part of the standard CI test matrix, catching platform-specific issues before release.
  • release-plz scope β€” Fixed to test all workspace crates, not just the nika binary crate.

πŸ“Š Test evolution

v0.55  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘  9,086 tests
v0.56  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘  9,093 tests (+7)
v0.56.2β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  9,109 tests (+16) ← you are here

Note

+16 tests specifically for serve hardening scenarios: CORS, auth edge cases, concurrent job submission, and SVG sanitization.


πŸ“¦ Install

Method Command
πŸš€ Quick curl -fsSL https://raw.githubusercontent.com/supernovae-st/nika/main/install.sh | sh
🍺 Homebrew brew install supernovae-st/tap/nika
πŸ“¦ npm npx @supernovae-st/nika
πŸ¦€ Cargo cargo install nika
🐳 Docker docker run --rm ghcr.io/supernovae-st/nika:0.56.2
πŸ’» VS Code Search "Nika" or ext install supernovae.nika-lang

Made with πŸ’œ by SuperNovae Studio β€” Open Source, AGPL-3.0

Full Changelog: v0.56.1...v0.56.2