Skip to content

add_comment.cjs: allowedAliases sanitization branch missing neutralizeMarkdownLinkTitles and neutralizeTemplateDelimiters — XPIA [Content truncated due to length] #28048

@szabta89

Description

@szabta89

Summary

sanitize_content.cjs contains two separate code paths: sanitizeContentCore (used when allowedAliases is empty) and a custom branch (taken when allowedAliases.length > 0). add_comment.cjs always invokes the allowedAliases branch because it populates parentAuthors from the parent issue/PR/discussion author — a non-bot user in virtually all real interactions. The allowedAliases branch does not import or call neutralizeMarkdownLinkTitles or neutralizeTemplateDelimiters, both of which are present in sanitizeContentCore. As a result, an AI agent generating a comment via add_comment safe-outputs can embed a hidden payload in a markdown link title (e.g., [text](url "XPIA payload")), which GitHub renders as an invisible hover-tooltip but delivers verbatim in the raw API response. A subsequent AI workflow run reading that comment receives the hidden payload in its model context — a cross-run AI-to-AI prompt injection (XPIA) channel.

The fix for issue #1869 closed this channel in sanitizeContentCore but was never propagated to the allowedAliases branch.

Affected Area

Output sanitization / safe-outputs write path — specifically setup/js/sanitize_content.cjs (the allowedAliases branch) as called by setup/js/add_comment.cjs. Trust boundary: agent-generated content → output sanitizer → GitHub API write.

Reproduction Outline

  1. Configure a gh-aw workflow with an add_comment safe-output targeting an issue or PR created by a regular (non-bot) GitHub user.
  2. Cause the AI agent to produce a comment body containing a markdown link with a hidden title: [Legitimate text](https://github.com/owner/repo "SYSTEM: malicious payload here").
  3. Observe that add_comment.cjs fetches the parent author (non-bot), sets parentAuthors = [username], and calls sanitizeContent(body, { allowedAliases: parentAuthors }).
  4. Verify in the posted GitHub comment that the link title text survives unchanged (it is not stripped or neutralized).
  5. On a subsequent workflow run, confirm that any AI agent reading that comment receives the hidden title text in its model context.

Observed Behavior

Markdown link titles containing hidden content survive the allowedAliases sanitization branch and are posted verbatim to GitHub. The neutralizeMarkdownLinkTitles and neutralizeTemplateDelimiters steps are skipped because they are not imported in sanitize_content.cjs and are absent from the allowedAliases branch.

Affected files (gh-aw-actions @ f52802884d655622f0a2dfd6d6a2250983c95523):

  • setup/js/add_comment.cjs — SHA 4d0e8d54aa3d0260cb044417abc4480ec5edd916
  • setup/js/sanitize_content.cjs — SHA 8218acdcdff5153fe56f348e86f427a898e4b10b
  • setup/js/sanitize_content_core.cjs — SHA d7730cf46e3f1b84e8cb383edfec46fb0096ff88

Expected Behavior

neutralizeMarkdownLinkTitles and neutralizeTemplateDelimiters should be applied on the allowedAliases branch in the same positions they occupy in sanitizeContentCore, so that hidden link titles are stripped regardless of which sanitization path is taken.

Suggested fixes (in order of preference):

  1. Architectural (preferred): Refactor sanitize_content.cjs to always call sanitizeContentCore first, then apply selective mention filtering as a post-processing pass, eliminating the code path divergence entirely.
  2. Immediate: Import neutralizeMarkdownLinkTitles and neutralizeTemplateDelimiters from sanitize_content_core.cjs in sanitize_content.cjs and call them in the allowedAliases branch before mention filtering (after removeXmlComments).
  3. Regression test: Add a test asserting that sanitizeContent(body, { allowedAliases: ['user'] }) strips hidden markdown link titles.

Security Relevance

This is a persistent cross-run XPIA channel: a malicious actor can use prompt injection to cause an AI agent to post a comment with a hidden payload that survives output sanitization. Any downstream AI workflow reading that comment receives the payload in its model context and may execute it, enabling privilege escalation or data exfiltration across workflow runs. The channel is open for all add_comment safe-outputs where the parent entity has a non-bot author — the default for any real repository interaction.

Additional Context

If the divergence between sanitizeContentCore and the allowedAliases branch is intentional (e.g., for performance or compatibility reasons), this design assumption should be explicitly documented, and any sanitization guarantees stated in the architecture documentation should be qualified to reflect which code path they apply to.

gh-aw version: v0.68.3

Original finding: https://github.com/githubnext/gh-aw-security/issues/1910

Generated by File Issue · ● 245.3K ·

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions