Guides

Behaviour Changes

Documented behaviour changes per release, and what they mean for existing invocations.

Behaviour Changes

This page records changes that alter observable behaviour, so an existing invocation can be audited against a release rather than discovered to have changed.

0.3.0

Two items. Both are narrow, and the second is the only one that can affect an existing invocation — read it if you already call validate() or analyze() programmatically.

1. Bad-character validation takes a set, and the list form is gone

Before 0.3.0, the parameter accepted a list of single-character strings (["x00"]) and the check was a substring test. The parameter now takes a specification string in any of the documented notations (\x00\x0a, 0x00,0x0a, 00 0a, 00,0a) and reports exact offsets, not merely presence.

# Before — list of string fragments
bot.validate(["x00"])

# 0.3.0 — specification string, all notations
bot.validate(r"\x00\x0a")

An existing call passing the list form is not silently reinterpreted. There is no compatibility shim: the old form is removed.

A bad character still does not abort the CLI run — the report is printed and the run continues, which is unchanged. It does mean a payload containing a forbidden byte is still written for inspection; the report tells you what to fix. See Bad Characters.

2. validate() and analyze() now cover the padding filler

If a filler has been applied with pad(), validation and analysis operate on filler + payload, not the payload alone.

This is deliberate: the padded bytes are what gets written and executed, so validating anything less would miss a filler that introduces a forbidden byte. It only changes results when padding is actually applied.

Padding itself is opt-in. Without --pad-size (CLI) or pad() (Python), output is byte-for-byte identical to 0.2.2 — so the overwhelming majority of existing invocations are unaffected by either item.

Also in 0.3.0

Additive, no behaviour change to existing invocations:

  • ShellSnip.pad(size, strategy, bad_chars) and ShellSnip.output().
  • CLI --pad-size N and --pad-with {none,nop,inert}.
  • MCP tools pad_shellcode and list_padding_strategies (thirteen tools total).
  • ShellSnip.analyze() returning BadCharReport with per-byte offsets and counts.
  • CLI subcommands asm and disasm; MCP tools assemble_block and disassemble.
  • The opt-in execution suite (SHELLSNIP_RUN_EXECUTION=1) and the loader's --cave N, --fill HEX, --breakpoint options. With none of these options the loader behaves as before.

Version metadata

pyproject.toml, __metadata.py, README.md and docs/index.md now all read 0.3.0. They previously disagreed: docs/index.md said 0.1.1 and the README badge said 0.2.0, both of which had been left behind by earlier releases.

The poetry-bumpversion configuration was also corrected: its README replacement targeted a Version: {current_version} line that no longer exists (the README badge replaced it), so future bumps would have silently skipped the README. It now targets the badge, separately from docs/index.md.

Copyright © 2026