Skip to content

fix: close XPIA steganographic channel in allowedAliases sanitization path#28055

Merged
pelikhan merged 4 commits intomainfrom
copilot/fix-neutralize-markdown-link-titles
Apr 23, 2026
Merged

fix: close XPIA steganographic channel in allowedAliases sanitization path#28055
pelikhan merged 4 commits intomainfrom
copilot/fix-neutralize-markdown-link-titles

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 23, 2026

Markdown link titles ([text](url "PAYLOAD")) are invisible in GitHub's rendered UI but delivered verbatim to AI model context, creating a persistent cross-prompt injection channel. neutralizeMarkdownLinkTitles was present in sanitizeContentCore but absent from the parallel allowedAliases pipeline in sanitize_content.cjs — meaning any call with allowedAliases (all safe-output write paths) bypassed this control entirely.

Changes

  • sanitize_content.cjs: Import neutralizeMarkdownLinkTitles from core and add applyToNonCodeRegions(sanitized, neutralizeMarkdownLinkTitles) to the allowedAliases pipeline, ordered after removeXmlComments and before neutralizeMentions — matching sanitizeContentCore.
  • sanitize_content.test.cjs: Three regression tests for the allowedAliases path covering inline titles, reference-style definitions, and @mention-bearing titles.

Before (allowedAliases path):

sanitizeContent('[Result](https://github.com "XPIA: inject")', { allowedAliases: ["author"] })
// → '[Result](https://github.com "XPIA: inject")'  — title preserved, hidden payload persists

After:

sanitizeContent('[Result](https://github.com "XPIA: inject")', { allowedAliases: ["author"] })
// → '[Result (XPIA: inject)](https://github.com)'  — title moved to visible text, no longer steganographic

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • invalid.example.invalid
    • Triggering command: /usr/lib/git-core/git-remote-https /usr/lib/git-core/git-remote-https origin https://invalid.example.invalid/nonexistent-repo.git git conf�� user.name lure tions/setup/js/node_modules/.bin/git -M main tnet/tools/git git init�� --bare --initial-branch=main k/gh-aw/gh-aw/actions/setup/js/node_modules/.bin/git user.name Test User ndor/bin/git git (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

…se XPIA channel

The allowedAliases branch in sanitize_content.cjs was missing a call to
neutralizeMarkdownLinkTitles, leaving markdown link titles (invisible
hover-text) unstripped — an XPIA steganographic injection channel.

- Import neutralizeMarkdownLinkTitles from sanitize_content_core.cjs
- Call applyToNonCodeRegions(sanitized, neutralizeMarkdownLinkTitles)
  after removeXmlComments and before neutralizeMentions in the
  allowedAliases pipeline (matching sanitizeContentCore ordering)
- Add three regression tests covering inline titles, reference-style
  titles, and @mention titles with allowedAliases specified

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/583c7f4c-10fe-4aad-ab16-746044faffce

Co-authored-by: szabta89 <1330202+szabta89@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix absence of neutralizeMarkdownLinkTitles in v0.68.3 fix: close XPIA steganographic channel in allowedAliases sanitization path Apr 23, 2026
Copilot AI requested a review from szabta89 April 23, 2026 12:15
@pelikhan pelikhan marked this pull request as ready for review April 23, 2026 12:25
Copilot AI review requested due to automatic review settings April 23, 2026 12:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Closes a cross-prompt injection channel where Markdown link titles ([text](url "TITLE")) were not being neutralized when allowedAliases is used, allowing hidden payloads to persist in otherwise “safe output” sanitization paths.

Changes:

  • Add neutralizeMarkdownLinkTitles into the allowedAliases sanitization pipeline in sanitize_content.cjs, matching sanitizeContentCore ordering.
  • Add regression tests covering inline link titles, reference-style definitions, and titles containing @mentions under the allowedAliases path.
Show a summary per file
File Description
actions/setup/js/sanitize_content.cjs Adds markdown link-title neutralization to the allowedAliases branch before mention filtering.
actions/setup/js/sanitize_content.test.cjs Adds regression tests ensuring link-title neutralization occurs when allowedAliases is specified.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 1

Comment thread actions/setup/js/sanitize_content.cjs Outdated
Comment on lines +98 to +99
// Remove markdown link titles — a steganographic injection channel analogous to HTML comments.
// Must run before mention neutralization for the same ordering reason as removeXmlComments.
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

The comment says "Remove markdown link titles", but neutralizeMarkdownLinkTitles does not always remove them (inline-link titles are moved into the visible link text, while reference-style titles are stripped). Consider updating the wording to match the function’s behavior (and the more detailed comment in sanitize_content_core.cjs).

Suggested change
// Remove markdown link titles — a steganographic injection channel analogous to HTML comments.
// Must run before mention neutralization for the same ordering reason as removeXmlComments.
// Neutralize markdown link titles as a hidden/steganographic injection channel analogous to
// HTML comments: inline-link titles are made visible in link text, while reference-style
// titles are stripped. Must run before mention neutralization for the same ordering reason
// as removeXmlComments.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 80/100

Excellent

Metric Value
New/modified tests analyzed 3
✅ Design tests (behavioral contracts) 3 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 3 (100%)
Duplicate test clusters 0
Test inflation detected ⚠️ Yes (25 test lines / 5 production lines = 5:1)
🚨 Coding-guideline violations None

Test Classification Details

View all 3 tests
Test File Classification Issues Detected
should neutralize markdown link titles when allowedAliases is specified (XPIA regression) sanitize_content.test.cjs ✅ Design None — explicit regression guard with behavioral assertion
should strip reference-style link titles when allowedAliases is specified sanitize_content.test.cjs ✅ Design None — asserts both negative containment and exact output
should neutralize link title @mentions via allowedAliases path without exposing the title steganographically sanitize_content.test.cjs ✅ Design None — verifies allowed-alias preservation in visible text

Flagged Tests — Requires Review

No tests flagged. All new tests are behavioral contract tests.

Note on test inflation: The test file grew 5× the production file (25 lines vs 5 lines). This is expected and acceptable for security regression tests — they document a vulnerability and require explicit before/after assertions to prevent regressions. The inflation penalty (−10 pts) was applied per rubric, but no manual review is needed.


Language Support

Tests analyzed:

  • 🟨 JavaScript (*.test.cjs): 3 tests (vitest)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). All 3 new tests are behavioral regression guards that directly assert observable output of sanitizeContent() under the allowedAliases branch — the exact path that previously leaked the XPIA steganographic channel.

References: §24835090389

🧪 Test quality analysis by Test Quality Sentinel · ● 321.5K ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 80/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 3 new tests are behavioral regression guards with direct output assertions.

@github-actions github-actions Bot mentioned this pull request Apr 23, 2026
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all comments

…wedAliases pipeline

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/f15821db-6c5f-413b-9d2d-469be2140fd7

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 23, 2026

@copilot review all comments

Updated the comment wording in 1e0f7bd to accurately reflect that inline-link titles are moved into visible link text (not removed), while reference-style titles are stripped — matching the suggestion from the review.

Copilot AI requested a review from pelikhan April 23, 2026 13:21
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

…e-markdown-link-titles

# Conflicts:
#	actions/setup/js/sanitize_content.cjs

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 23, 2026

@copilot merge main and recompile

Done in d6ff358. Merged main (resolved a comment-only conflict in sanitize_content.cjs), rebuilt the binary, and recompiled workflows. All 369 tests pass.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw -embedcfg /tmp/go-build1494851885/b349/embedcfg -pack (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv (http block)

If you need me to access, download, or install something from one of these locations, you can either:

@pelikhan pelikhan merged commit b0ba3fc into main Apr 23, 2026
@pelikhan pelikhan deleted the copilot/fix-neutralize-markdown-link-titles branch April 23, 2026 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants