FEAT: add AcrosticConverter - #2280
Open
Ivanodib wants to merge 4 commits into
Open
Conversation
Author
|
@microsoft-github-policy-service agree company="Microsoft" |
Contributor
|
thanks for contributing @Ivanodib! Curious: do you have a link to the paper where this method is documented? or is this something you tried in your own red teaming? |
jsong468
reviewed
Jul 29, 2026
jsong468
reviewed
Jul 29, 2026
jsong468
reviewed
Jul 29, 2026
jsong468
reviewed
Jul 29, 2026
Author
Thanks @jsong468! No specific paper, and I couldn't find a source for the input-side use specifically. I added it as the encoder counterpart of the existing FirstLetterConverter. I tested it with benign canaries on a few recent models (Kimi-K2.6, DeepSeek-V4-Pro, Grok-4.3, GPT-5.1, GPT-5.4) and they reconstruct and follow the hidden instruction. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds
AcrosticConverter, a text-to-text converter that hides the prompt as an acrostic. Each character of the prompt becomes its own line — an alphabetic character is expanded into a benign word starting with that character, and a space is rendered as a sentinel line — so the original message is legible only when reading the first character of each line from top to bottom. A leading instruction tells the model to reconstruct the hidden message and follow it.For example,
await AcrosticConverter().convert_async(prompt="cut a tree")produces:Reading the first character of each line gives
CUT A TREE.This is the encoder counterpart of the existing
FirstLetterConverter, which reduces text down to its first letters. The intended use is evaluating whether a content filter or a model detects a request hidden in acrostic form: a filter scanning the visible text sees an innocuous word list, while the real request only exists vertically.Both the leading instruction and the word bank are constructor parameters, so the surface text can be varied by the caller.
Scope and limitations. This is a text transformation primitive for red-team evaluation, not a validated bypass — effectiveness against any given filter or model should be measured empirically rather than assumed. The default word bank is deliberately minimal (one word per letter), which makes the output repetitive and fairly recognizable; callers wanting less conspicuous output should pass a richer bank via
word_bank.decode()is a round-trip helper tailored to this converter's own output format, not a general-purpose acrostic parser.I did not open an issue before submitting — happy to do that first if maintainers prefer.
Tests and Documentation
Tests — new file
tests/unit/converter/test_acrostic_converter.pywith 7 unit tests covering: the returnedConverterResultshape, first letters spelling the message, space encoding via the sentinel line, the encode → decode round trip, dropping of non-alphabetic characters, a custom instruction, and a custom word bank.Documentation — registered in
pyrit/converter/__init__.py(import +__all__) and added todoc/code/converters/1_text_to_text_converters.pyunder §1.2 Obfuscation Converters, next toFirstLetterConverter. This satisfiestests/unit/docs/test_converter_documentation.py, which requires every converter to appear in a converter notebook.JupyText — I updated the
.pypercent file but did not re-execute the notebook to regenerate1_text_to_text_converters.ipynb. That notebook's LLM-Based Converters section connects to live endpoints I don't have configured, and re-executing it would rewrite the outputs of every cell and bloat the diff well beyond this change. Happy to regenerate it if a maintainer prefers, otherwise it should be covered by the pre-release regeneration pass described indoc/contributing/7_notebooks.md.Checks run locally
uv run pytest tests/unit/converter tests/unit/docs tests/unit/registry→ 1488 passeduv run pre-commit run --files <changed files>→ all hooks pass, includingruff-format,ruff-check,ty,check-no-rest-rolesandcheck-async-suffix