Skip to content

FEAT add CodeAttackConverter (closes #1945) - #1960

Open
Utkarsh Bahuguna (u7k4rs6) wants to merge 12 commits into
microsoft:mainfrom
u7k4rs6:feat/code-attack
Open

FEAT add CodeAttackConverter (closes #1945)#1960
Utkarsh Bahuguna (u7k4rs6) wants to merge 12 commits into
microsoft:mainfrom
u7k4rs6:feat/code-attack

Conversation

@u7k4rs6

@u7k4rs6 Utkarsh Bahuguna (u7k4rs6) commented Jun 9, 2026

Copy link
Copy Markdown

Closes #1945.

Summary

Implements CodeAttack (Ren et al., ACL 2024, arXiv:2403.07865), which reformulates a harmful query as a code-completion task. The query is encoded into a data-structure initialization sequence inside a partial code template with a decode() stub, and the target is asked to complete the code. Because the intent is expressed as a programming task rather than a natural-language request, safety training keyed to natural language triggers less reliably. Black-box, no compute requirements.

Two notes for review (deltas from the issue)

  1. Encoding is word-by-word, not character-by-character. The issue described it as char-by-char (from the paper abstract), but the reference implementation (renqibing/CodeAttack) splits on whitespace and hyphens via regex, with character-level only as a fallback for single-token inputs. I matched the reference code. One consequence: the two token-splitting encodings normalize separators. PYTHON_LIST calls str.split(), so it collapses any run of whitespace and drops leading and trailing whitespace, though hyphens survive inside tokens. PYTHON_STACK does the same and additionally consumes hyphens as delimiters, and reverses token order. The three string encodings (PYTHON_STRING, CPP, GO) embed the prompt as a single literal and round-trip byte-identically. The converter docstring spells out which inputs are lossless under which encoding.

  2. Eight templates, not five. The issue scoped five (one per language), but the reference ships eight: the three Python types each have a base and a _plus verbose variant, and cpp and go have no verbose variant upstream. I included all eight to match the reference. Happy to drop the three _plus files if you would rather keep it to five.

Design

  • CodeAttackConverter in pyrit/converter/code_attack_converter.py. It encodes the prompt into a data-structure initialisation sequence and renders a partial code template with a decode() stub. It is a standalone Converter and composes through the normal converter pipeline.

  • Template selection is the CodeAttackConverter.Template enum, which has eight members:

    Member Template file
    PYTHON_STACK code_attack_python_stack
    PYTHON_STACK_VERBOSE code_attack_python_stack_plus
    PYTHON_LIST code_attack_python_list
    PYTHON_LIST_VERBOSE code_attack_python_list_plus
    PYTHON_STRING code_attack_python_string
    PYTHON_STRING_VERBOSE code_attack_python_string_plus
    CPP code_attack_cpp
    GO code_attack_go

    The default is PYTHON_STACK_VERBOSE. A pathlib.Path can be passed instead to supply a custom template file.

  • Encoding is a separate axis from the template. CodeAttackConverter.Encoding is a new public enum with five members: PYTHON_STACK, PYTHON_LIST, PYTHON_STRING, CPP, GO. For a built-in Template the matching encoding is derived automatically and does not need to be passed. For a pathlib.Path it is required, because the data structure cannot be inferred from a custom file; passing a Path without encoding= raises ValueError rather than silently defaulting.

  • Eight seed prompts in pyrit/datasets/converters/, matching the CodeChameleon convention:
    code_attack_python_stack.yaml, code_attack_python_stack_plus.yaml,
    code_attack_python_list.yaml, code_attack_python_list_plus.yaml,
    code_attack_python_string.yaml, code_attack_python_string_plus.yaml,
    code_attack_cpp.yaml, code_attack_go.yaml.

  • No attack class. Per review feedback the earlier CodeAttackAttack subclass was dropped, and the technique is registered as the code_attack factory in pyrit/setup/initializers/techniques/core.py, wiring the converter onto PromptSendingAttack.

Tests

63 unit tests in tests/unit/converter/test_code_attack_converter.py, covering per-template rendering, base vs _plus variants, word-recovery round-trips, separator normalization, empty, special-character and long prompts, custom pathlib.Path templates, unsupported input types, and identifier construction.

Factory coverage is split across two files. TestCodeAttackTechnique in tests/unit/setup/techniques/test_core_techniques.py holds the focused wiring tests (2): one asserting the factory shape (attack class, tags, description, and the single wired CodeAttackConverter with its template and encoding), and one asserting the wired converter actually encodes the objective. It sits next to the existing flip technique tests, which is where this repo keeps per-technique factory tests. Separately, tests/unit/setup/test_technique_initializer.py contributes the registry-level check, where code_attack is added to CORE_TECHNIQUE_NAMES and asserted against the built factory set in six places.

Two documentation surfaces:

  • doc/code/converters/1_text_to_text_converters.py, section 1.2 Obfuscation Converters, next to CodeChameleon. The converter is template-based and runs offline, so the cell carries real executed output.
  • The Code section in doc/code/executor/1_single_turn.py, showing the converter applied through AttackConverterConfig.

The ren2024codeattack entry in doc/references.bib cites the published ACL 2024 Findings paper.

Review round 2

  • Language-aware string-literal escaping. All five encoders used json.dumps() with the default
    ensure_ascii=True, so a non-BMP character became a surrogate pair (\ud83d\ude00). Python evaluates that
    to two lone surrogates, and Go and C++ reject surrogate escapes outright, so emoji input produced code that
    would not compile. The encoders now share one escaping helper that emits literal UTF-8 and escapes only
    backslash, double quote and control characters. C++ uses three-digit octal for control characters, since its
    hex escapes consume an unbounded run of hex digits and would swallow a following literal digit. Verified by
    compiling the generated C++ and Go under -Wall -Wextra -Werror and go vet, then asserting byte-identical
    round-trips for emoji, newline, tab, backslash, double quote, control and DEL input.

  • Template loaded and validated in __init__. SeedPrompt.from_yaml_file() moved out of convert_async
    and is cached on the instance, so it no longer parses YAML synchronously on every conversion and a missing or
    malformed custom file fails at construction. Construction also rejects a template whose body never references
    wrapped_input, which previously rendered a constant string and silently discarded the objective.

  • Content-based identifier. _build_identifier() no longer embeds an absolute template path, which differed
    across worktrees and did not change when a custom file's contents changed. It now reports the stable enum name,
    a sha256[:16] of the loaded template value, and the encoding, matching TemplateSegmentConverter's shape.

  • Note on 0_converters.ipynb. Regenerating the modality table also picked up two converter rows the
    committed output predated: AcrosticConverter (FEAT: add AcrosticConverter #2280) and VigenereConverter (FEAT: Add VigenereConverter #2333). Nothing was removed.
    Those rows are unrelated to this PR but the table is generated, so trimming them would mean hand-editing
    generated output.

Files

New (10):

  • pyrit/converter/code_attack_converter.py
  • pyrit/datasets/converters/code_attack_cpp.yaml
  • pyrit/datasets/converters/code_attack_go.yaml
  • pyrit/datasets/converters/code_attack_python_list.yaml
  • pyrit/datasets/converters/code_attack_python_list_plus.yaml
  • pyrit/datasets/converters/code_attack_python_stack.yaml
  • pyrit/datasets/converters/code_attack_python_stack_plus.yaml
  • pyrit/datasets/converters/code_attack_python_string.yaml
  • pyrit/datasets/converters/code_attack_python_string_plus.yaml
  • tests/unit/converter/test_code_attack_converter.py

Modified (11):

  • pyrit/converter/__init__.py
  • pyrit/setup/initializers/techniques/core.py
  • tests/unit/setup/techniques/test_core_techniques.py
  • tests/unit/setup/test_technique_initializer.py
  • doc/references.bib
  • doc/bibliography.md
  • doc/code/converters/0_converters.ipynb
  • doc/code/converters/1_text_to_text_converters.py
  • doc/code/converters/1_text_to_text_converters.ipynb
  • doc/code/executor/1_single_turn.py
  • doc/code/executor/1_single_turn.ipynb

Notes

Rebased onto main after the PromptConverter to Converter rename (upstream 3acaaa6), so the converter lives under pyrit/converter/, subclasses Converter, and the seed prompts moved to pyrit/datasets/converters/.

Total diff: 21 files changed, 1450 insertions(+), 68 deletions(-).

Checklist

  • pre-commit hooks pass
  • Unit tests added and passing locally
  • No regressions
  • Docstrings on the converter
  • Notebook demonstrating usage

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Risk Summary

Quality Score: 9/10
Risk Level: low
Merge Recommendation: Safe to merge
Rationale: The changes appear to be focused on adding and refining code attack functionalities and their associated prompt converters. The review found no issues, and the changes are well-contained within the relevant modules. The addition of unit tests further strengthens the quality of this pull request.

Comment thread doc/myst.yml Outdated
@romanlutz

Copy link
Copy Markdown
Contributor

We need a references.bib update to include the paper.

Comment thread pyrit/executor/attack/single_turn/__init__.py Outdated
Comment thread pyrit/executor/attack/single_turn/code_attack.py Outdated
Comment thread pyrit/executor/attack/single_turn/code_attack.py Outdated
Comment thread pyrit/executor/attack/single_turn/code_attack.py Outdated
Utkarsh Bahuguna (u7k4rs6) added a commit to u7k4rs6/PyRIT that referenced this pull request Jun 22, 2026
…te enum, add bib entry, docs

- Rename CodeAttackAttack -> CodeAttack (Task 1)
- Collapse language + verbose into a single CodeAttackConverter.Template enum
  modelled on BinaryConverter.BitsPerChar; custom pathlib.Path still accepted
  for caller-supplied YAML templates (Task 2)
- CodeAttack.__init__ now accepts template: CodeAttackConverter.Template | Path
  and forwards it to the converter; language/verbose params removed (Task 3)
- Add @ren2024codeattack entry to doc/references.bib after liu2024flipattack (Task 4)
- Add Code row to the attack table in 1_single_turn.py, add ## Code section
  after ## Flip mirroring the FlipAttack shape, regenerate notebook (Task 5)
- Rebase onto upstream/main (doc/code/executor/attack/ directory was removed
  upstream; old standalone code_attack.ipynb/.py deleted, content moved into
  1_single_turn.py)
- Update all unit tests for the new Template-based API; add custom-Path cases
@u7k4rs6

Copy link
Copy Markdown
Author

Roman Lutz (@romanlutz) Thanks for the thorough pass. Addressed everything:

Rebased on main; folded the docs into 1_single_turn next to Flip, removed the separate file and myst.yml entry
Added the ren2024codeattack reference and cited it in the docstrings
Renamed CodeAttackAttack to CodeAttack
Collapsed language + verbose into a single enum-typed template param (CodeAttackConverter.Template) that also accepts a custom Path
Kept the attack class but structured it like FlipAttack (system prompt via _setup_async); left the converter independently usable

Open to dropping the class for converter-only if you'd rather. Re-requesting review.

Comment thread pyrit/datasets/executors/code_attack.yaml Outdated
Comment thread pyrit/executor/attack/single_turn/code_attack.py Outdated
@u7k4rs6

Copy link
Copy Markdown
Author

Tracked the framing variant in #2088. Resolving.

Utkarsh Bahuguna (u7k4rs6) added a commit to u7k4rs6/PyRIT that referenced this pull request Jul 10, 2026
…te enum, add bib entry, docs

- Rename CodeAttackAttack -> CodeAttack (Task 1)
- Collapse language + verbose into a single CodeAttackConverter.Template enum
  modelled on BinaryConverter.BitsPerChar; custom pathlib.Path still accepted
  for caller-supplied YAML templates (Task 2)
- CodeAttack.__init__ now accepts template: CodeAttackConverter.Template | Path
  and forwards it to the converter; language/verbose params removed (Task 3)
- Add @ren2024codeattack entry to doc/references.bib after liu2024flipattack (Task 4)
- Add Code row to the attack table in 1_single_turn.py, add ## Code section
  after ## Flip mirroring the FlipAttack shape, regenerate notebook (Task 5)
- Rebase onto upstream/main (doc/code/executor/attack/ directory was removed
  upstream; old standalone code_attack.ipynb/.py deleted, content moved into
  1_single_turn.py)
- Update all unit tests for the new Template-based API; add custom-Path cases
Utkarsh Bahuguna (u7k4rs6) added a commit to u7k4rs6/PyRIT that referenced this pull request Aug 9, 2026
…te enum, add bib entry, docs

- Rename CodeAttackAttack -> CodeAttack (Task 1)
- Collapse language + verbose into a single CodeAttackConverter.Template enum
  modelled on BinaryConverter.BitsPerChar; custom pathlib.Path still accepted
  for caller-supplied YAML templates (Task 2)
- CodeAttack.__init__ now accepts template: CodeAttackConverter.Template | Path
  and forwards it to the converter; language/verbose params removed (Task 3)
- Add @ren2024codeattack entry to doc/references.bib after liu2024flipattack (Task 4)
- Add Code row to the attack table in 1_single_turn.py, add ## Code section
  after ## Flip mirroring the FlipAttack shape, regenerate notebook (Task 5)
- Rebase onto upstream/main (doc/code/executor/attack/ directory was removed
  upstream; old standalone code_attack.ipynb/.py deleted, content moved into
  1_single_turn.py)
- Update all unit tests for the new Template-based API; add custom-Path cases
@u7k4rs6

Copy link
Copy Markdown
Author

Roman Lutz (@romanlutz) Rebased onto current main. The branch was ~150 commits behind, so this
absorbs the PromptConverterConverter rename from #2161 across all
three directory moves and both symbol renames, and drops the FlipAttack
and ContextComplianceAttack hunks now that those are gone upstream.

Also fixed a gap that predates the rebase: test_all_converters_are_documented
was failing because CodeAttackConverter had no entry under
doc/code/converters/. Added an example to 1_text_to_text_converters,
plus a description= on the code_attack factory so it matches the others.

Converter, docs and setup suites green, pre-commit clean. Description
updated for the new names.

@u7k4rs6

Utkarsh Bahuguna (u7k4rs6) commented Aug 22, 2026

Copy link
Copy Markdown
Author

hey Roman Lutz (@romanlutz) , no rush on the review itself, but #1960's CI is stuck awaiting maintainer approval so nothing has actually run on it yet. could you kick that off when you get a sec? also cleaned up the description, the attack class is gone and it's a converter + technique factory now, plus updated the bib entry to the ACL Findings version to match your #2409 pass 🙏

@u7k4rs6 Utkarsh Bahuguna (u7k4rs6) changed the title FEAT add CodeAttackConverter and CodeAttackAttack (closes #1945) FEAT add CodeAttackConverter (closes #1945) Aug 22, 2026
Comment thread pyrit/converter/code_attack_converter.py Outdated
},
{
"cell_type": "code",
"execution_count": null,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new cell is committed with execution_count: null and no output. The documentation instructions require retaining executed notebook outputs. Please execute and regenerate the paired notebook using this checkout.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cell runs a live PromptSendingAttack against OpenAIChatTarget and I don't have target credentials, so I can't produce real output for it. I didn't want to fabricate one. Options as I see them: someone with a configured target executes the cell and pushes to the branch (edits by maintainers is on), or the cell becomes an offline convert_async demo, or it ships unexecuted. Any of those works for me, let me know which you prefer. For what it's worth tests/unit/docs passes green as-is and nothing in the hooks or tests inspects execution_count.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll rerun this notebook before merging, so this is not a problem for the implementation. Leaving the thread open so we don't forget the pre-merge step.

Comment thread doc/code/converters/1_text_to_text_converters.py
Comment thread tests/unit/converter/test_code_attack_converter.py Outdated
Comment thread pyrit/converter/code_attack_converter.py Outdated
Comment thread pyrit/converter/code_attack_converter.py Outdated
Comment thread pyrit/converter/code_attack_converter.py Outdated
Comment thread pyrit/converter/code_attack_converter.py
Comment thread doc/references.bib
Implement CodeAttack (Ren et al., ACL 2024) as a standalone converter
and a PromptSendingAttack subclass following the FlipAttack pattern.

CodeAttackConverter encodes a natural-language prompt word-by-word into
a data-structure initialisation sequence (deque appends, list appends,
or a string assignment) and embeds it in a partial code template that
asks the model to complete the code. Five language variants are
supported: python_stack, python_list, python_string, cpp, go. The
verbose flag selects the _plus template (detailed paragraphs) for the
three Python variants; cpp and go have no plus variant upstream.

CodeAttackAttack wraps the converter in a PromptSendingAttack, prepends
a system prompt that frames the session as code completion, and forwards
language and verbose to the converter. Callers supply a scorer via
AttackScoringConfig as usual.

Files added:
  pyrit/prompt_converter/code_attack_converter.py
  pyrit/executor/attack/single_turn/code_attack.py
  pyrit/datasets/executors/code_attack.yaml
  pyrit/datasets/prompt_converters/code_attack_python_stack{,_plus}.yaml
  pyrit/datasets/prompt_converters/code_attack_python_list{,_plus}.yaml
  pyrit/datasets/prompt_converters/code_attack_python_string{,_plus}.yaml
  pyrit/datasets/prompt_converters/code_attack_cpp.yaml
  pyrit/datasets/prompt_converters/code_attack_go.yaml
  tests/unit/prompt_converter/test_code_attack_converter.py (23 tests)
  tests/unit/executor/attack/single_turn/test_code_attack.py (16 tests)
  doc/code/executor/attack/code_attack.py
  doc/code/executor/attack/code_attack.ipynb

Files modified:
  pyrit/prompt_converter/__init__.py
  pyrit/executor/attack/single_turn/__init__.py
  pyrit/executor/attack/__init__.py
  doc/myst.yml
…te enum, add bib entry, docs

- Rename CodeAttackAttack -> CodeAttack (Task 1)
- Collapse language + verbose into a single CodeAttackConverter.Template enum
  modelled on BinaryConverter.BitsPerChar; custom pathlib.Path still accepted
  for caller-supplied YAML templates (Task 2)
- CodeAttack.__init__ now accepts template: CodeAttackConverter.Template | Path
  and forwards it to the converter; language/verbose params removed (Task 3)
- Add @ren2024codeattack entry to doc/references.bib after liu2024flipattack (Task 4)
- Add Code row to the attack table in 1_single_turn.py, add ## Code section
  after ## Flip mirroring the FlipAttack shape, regenerate notebook (Task 5)
- Rebase onto upstream/main (doc/code/executor/attack/ directory was removed
  upstream; old standalone code_attack.ipynb/.py deleted, content moved into
  1_single_turn.py)
- Update all unit tests for the new Template-based API; add custom-Path cases
Correct the authors to match the ren2024codeattack bib entry:
Ren, Gao, Shao, Yan, Tan, Lam, Ma (SJTU / Shanghai AI Lab / CUHK).
Remove incorrect names (Liu, Fan, Chen, Zhong, Lu, Wen) and replace
Nanyang Technological University with Shanghai Jiao Tong University.
Remove CodeAttack attack class and its test file; wire code_attack as a
PromptSendingAttack + CodeAttackConverter entry in scenario_techniques.py.
Delete the now-orphaned executor system-prompt seed YAML. Update the
single-turn executor doc and regenerate the notebook to show the
converter-based usage pattern.
All five encoders (_encode_python_stack, _encode_python_list,
_encode_python_string, _encode_cpp, _encode_go) now use json.dumps() to
escape embedded double quotes and backslashes before interpolating into
string literals. A prompt containing a double quote no longer produces
malformed code.

Also fix the class docstring: separator normalisation on [\s\-]+ applies
only to python_stack; python_list uses str.split() and preserves hyphens.

Add tests for embedded double quotes in all five encoder paths.
…ues/core.py

Upstream (microsoft#2155) replaced initializers/components/scenario_techniques.py
with initializers/techniques/core.py and renamed strategy_tags to
technique_tags. The core group tag is now injected by build_technique_factories
rather than stored in the factory. Port the code_attack entry and its test
list update to the new layout.
Satisfies tests/unit/docs/test_converter_documentation.py, which requires
every converter in pyrit.converter.__all__ to appear in a notebook under
doc/code/converters/. The example lives in its own cell so the existing
section 1.2 cell (which contains non-deterministic converters) keeps its
stored output untouched.

The converter is template-based and runs offline, so the new cell carries
real executed output like every other cell on the page.
Every other factory in techniques/core.py carries a description; code_attack
was the only one without. Matches the sibling register: single sentence,
third-person present, states the mechanism.
…stable identifier

Addresses review feedback on microsoft#1960.

Escaping: every encoder used json.dumps() with the default ensure_ascii=True,
so a non-BMP character became a surrogate pair ("😀"). Python
evaluates that to two lone surrogates and Go and C++ reject surrogate escapes
outright, so emoji input produced code that would not compile. All five
encoders now route through one module-level _escape_string_literal() helper
that emits literal UTF-8 and escapes only backslash, double quote and control
characters. C++ uses three-digit octal for control characters because its hex
escapes consume an unbounded run of hex digits and would swallow a following
literal digit; Python and Go use two-digit hex, which their grammars bound.
Verified by compiling the generated C++ and Go under -Wall -Wextra -Werror and
go vet, then asserting byte-identical round-trips for emoji, newline, tab,
backslash, double quote, control and DEL characters.

Template loading: SeedPrompt.from_yaml_file() moved from convert_async into
__init__ and cached on the instance, so a missing or malformed custom file now
fails at construction instead of on first use. Construction also rejects a
template whose body never references wrapped_input, which previously rendered
a constant string and silently discarded the objective.

Identifier: _build_identifier() no longer embeds an absolute template path,
which was machine-dependent and did not change when a custom file's contents
changed. It now reports the stable enum name, a sha256 prefix of the loaded
template value and the encoding, matching TemplateSegmentConverter's shape.

Encoding: a custom pathlib.Path template was forced to python_string, so a
caller could not supply a custom stack, list, C++ or Go wrapper. Adds a
separate Encoding enum, maps each Template member to its Encoding, and
requires an explicit encoding= for Path templates rather than defaulting
silently. The Template enum and the PYTHON_STACK_VERBOSE default are
unchanged, so existing callers are unaffected.

Docstring: the separator-normalisation section claimed normalisation was
python_stack only. python_list also collapses whitespace runs via str.split();
the stack-specific part is that it additionally consumes hyphens and reverses
order. Rewritten per encoding so a caller can tell what round-trips losslessly.

Tests: 31 -> 64. Adds a real render parameterized over every Template member,
exact decoded-literal assertions in place of escaped-substring matching,
identifier stability across paths and sensitivity to content and encoding,
non-BMP round-trips per encoding, control-character round-trips, custom
template validation (missing file, malformed YAML, no wrapped_input, Path
without encoding) and a focused code_attack factory-wiring test.

Two existing tests changed because the behaviour they asserted is the bug
being fixed: test_custom_path_template_constructs and
test_custom_path_template_renders both relied on a Path template silently
defaulting to python_string, and now pass encoding= explicitly.
Adds @ren2024codeattack to the citation-key list in doc/bibliography.md,
keeping the list alphabetical (between @promptfoo2025ccp and
@robustintelligence2024bypass). The bib entry already existed; it was not
listed, so the citation did not render.

Regenerates the modality table in doc/code/converters/0_converters.ipynb,
whose stored output jumped from CharacterSpaceConverter straight to
CodeChameleonConverter. CodeAttackConverter now appears at row 36. Only that
cell was executed; the cells that need a live target were left untouched.
…literal

Coverage audit against the six review asks turned up two gaps.

The factory-wiring test was in the converter test file, but the repo keeps
core technique factory tests in tests/unit/setup/techniques/test_core_techniques.py
next to the flip technique. Moved it there as TestCodeAttackTechnique,
matching TestFlipTechnique's shape: one test for the factory wiring (attack
class, tags, description, the single wired CodeAttackConverter and its
template and encoding) and one that the wired converter actually encodes the
objective. Updated that module's docstring, which claimed it covered flip only.

Seven assertions in the round-trip and edge-case tests still extracted
literals with a ([^"]+) regex and compared the escaped form, which is exactly
what the review asked to stop doing and which silently breaks on any escape.
They now go through _decode_literals/_decode_assignment like the rest, so they
compare the value the target language would actually see. The three superseded
_extract_* helpers are gone, along with a duplicated _write_template.

No behaviour change; converter test file 64 -> 63 tests because the factory
test moved, core techniques 3 -> 5.
@u7k4rs6

Copy link
Copy Markdown
Author

Roman Lutz (@romanlutz) Addressed all of these. The substantive ones: language-aware escaping so non-BMP input survives Go and C++, eager template load with wrapped_input validation, content-hash identifier, and a new Encoding enum so custom Path templates aren't locked to python_string. Tests went 31 to 63 in the converter file plus 2 in core techniques.

One I can't close: the 1_single_turn cell needs a live target and I don't have credentials. Left options on that thread.

Also, CI still hasn't run on this PR at all. All five workflows are stuck awaiting maintainer approval, so none of this has been verified upstream yet. Could you kick that off?

if isinstance(template, CodeAttackConverter.Template):
self._template_path = pathlib.Path(CONVERTER_SEED_PROMPT_PATH) / f"{template.value}.yaml"
self._template_name: str = template.name
resolved_encoding = encoding if encoding is not None else _TEMPLATE_ENCODING[template]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we reject an encoding that does not match a built-in Template? For example, Template.PYTHON_STACK with Encoding.PYTHON_LIST produces:

my_stack = deque()
my_list.append("alpha")
task = decode(my_stack)

The objective is written to my_list but decoded from the empty my_stack, so the attack silently loses the objective. Custom paths need an explicit encoding, but built-in templates should use their mapped encoding or raise on a mismatch. Am I missing a valid use case for overriding a built-in this way?

"""
environment = SandboxedEnvironment()
referenced = meta.find_undeclared_variables(environment.parse(seed_prompt.value))
if _WRAPPED_INPUT not in referenced:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we also reject unsupported template variables during construction? The converter only supplies wrapped_input, so a custom template such as {{ wrapped_input }} {{ suffix }} passes this check and then fails on its first conversion because suffix is undefined. Checking for any remaining undeclared variables here would keep custom-template failures at construction time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FEAT CodeAttack

4 participants