[Improve] Frame third-party text in agent prompts as untrusted content#570
Conversation
GitHub issue bodies, PR discussion context, and automation work-item source context now land in agent prompts inside escaped delimiter blocks alongside a shared untrusted-content policy, so quoted external text is treated as data rather than instructions. The review-code skill gains matching constraints for reviewing externally authored pull requests.
|
No new code issues found. See task
Reviewed b134235 |
Addresses review feedback: the work-item title is now escaped inline and the brief and investigation context land inside escaped delimiter blocks. The execution prompt stays unwrapped because it is the automation's instruction channel; the provenance boundary for it belongs to the scan run that distills external sources into the work item.
|
Addressed in 58e7189. The work-item title is now escaped inline, and
|
Addresses the remaining review finding: automation work-item execution prompts are scan-agent output over external sources, so they no longer ride as a fully trusted instruction channel. They are delivered inside an escaped automation_execution_guidance block that the shared policy limits to the named work item, unable to expand scope or authorize new actions. Also extends the untrusted-content framing to the surfaces that arrived with the develop merge: the Triage GitHub Issues prompt now escapes the issue title, labels, author, and URL inside task_context, delimits the issue body, and carries the policy; repeat-mention issue follow-up messages get the same mention-request framing as the initial mention.
|
Conceded the The develop merge also brought in the Triage GitHub Issues automation, which is exactly the surface this PR exists for, so the same commit hardens it: |
What
Now that the repo is public, any GitHub user can author text that ends up inside Roomote agent prompts (issue bodies, PR descriptions, discussion comments, alert context). This PR adds a consistent trust boundary at the prompt layer so that quoted external text is framed as data to analyze, never as instructions to follow.
Changes
packages/cloud-agents/src/server/untrusted-content.ts:buildUntrustedExternalContentBlockwraps third-party text in an entity-escaped<untrusted_external_content source="...">block so embedded markup cannot forge prompt structurebuildMentionRequestBlockwraps the gate-verified requester's message in an escaped<mention_request>blockbuildUntrustedContentPolicyemits a standing<untrusted_content_policy>rules block (data-not-instructions, no scope expansion, flag injection attempts, never disclose secrets in public replies)handleGitHubIssueComment.ts): the issue body and mention comment were previously concatenated raw into the task prompt. Both are now escaped and delimited, the issue body is labeled with its author and marked context-only, and the policy block is appended. Also dedupes theissues.openedpath, which previously included the issue body twice (once as body, once as mention text).github-pr-follow-up-context.ts): both shared builders (new dedicated follow-up tasks and steers into existing tasks) now include the policy block. Content escaping already existed here.automation-work-items/launch.ts): execution task prompts now carry the policy block, since work items are distilled from external sources (issues, alerts, PR discussions).Notes
Testing
issue_commentandissues.openedshapespnpm lint,pnpm check-types,pnpm knip, and the full@roomote/cloud-agents+ affected@roomote/apisuites pass