Skip to content

fix: escape untrusted YAML values in generated workspace templates - #340

Open
o-mid wants to merge 3 commits into
theam:mainfrom
o-mid:fix/escape-generated-templates
Open

o-mid wants to merge 3 commits into
theam:mainfrom
o-mid:fix/escape-generated-templates

Conversation

@o-mid

@o-mid o-mid commented Sep 8, 2026

Copy link
Copy Markdown

Addresses #228.

Facility 0.12 no longer generates GitHub workflows or Claude settings, so the original doctor-watch, settings.json, and protect-branch regex vectors are gone. Model ids were still interpolated unquoted into agent YAML frontmatter, so values like a newline plus enabled: false, |, #, or $(id) could change structure or truncate the scalar.

This quotes every generated YAML scalar (models and environment commands) in both facility init and kickstart rendering, and adds hostile-input regressions through the CLI, core renderer, and agent parser.

Test plan

  • pnpm test --filter @theagilemonkeys/facility
  • pnpm test --filter @facility/core
  • pnpm test --filter @facility/agents
  • Confirm hostile model ids ($(id), foo"bar # pwned, newline + enabled: false, |) stay quoted scalars and parse as the original model string
  • Confirm ordinary ids (gpt-5.6-sol, dated claude-opus-4-8-20260101) still work after quoting
  • Confirm setup / start / ready commands with quotes and $(id) remain data, not shell

Quote model ids and environment commands as YAML scalars so hostile
input cannot inject keys, comments, or block scalars into kickstart
artifacts.

@adrian-lorenzo adrian-lorenzo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for adapting this to the current workspace templates.

CLI substitution still interprets values such as $& and {{CODEX_PLAN_MODEL}}, corrupting generated models. The doctor change also accepts invalid model values. Please use the core renderer’s single-pass callback approach, preserve model validation, and add regression tests for both.

o-mid and others added 2 commits September 15, 2026 11:03
String replaceAll treated $& as the match and re-expanded nested
placeholders. Doctor now parses the model as a YAML string so comments
and unclosed quotes fail while quoted names with spaces still pass.
@o-mid

o-mid commented Sep 15, 2026

Copy link
Copy Markdown
Author

@adrian-lorenzo,
CLI init used String.replaceAll, so $& became the matched placeholder and a model value of {{CODEX_PLAN_MODEL}} got substituted again when that key was applied. It now uses the same single-pass callback as the core renderer.

Doctor parses model as a YAML string (1–160 chars). Comment-only lines and unclosed quotes fail; quoted names with spaces still pass.

Added regressions for both in the CLI, and the $& / nested placeholder case in core.

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.

2 participants