Skip to content

fix(security): wrap the structured JSON block of TM plan tools (complete injection wrap) - #437

Merged
gaurav-singh-9227 merged 1 commit into
browserstack:mainfrom
SavioBS629:security/wrap-tm-plan-structured
Sep 25, 2026
Merged

gaurav-singh-9227 merged 1 commit into
browserstack:mainfrom
SavioBS629:security/wrap-tm-plan-structured

Conversation

@SavioBS629

Copy link
Copy Markdown
Collaborator

What & why

Follow-up to the TM prompt-injection hardening (GHSA-9w6g-vr6g-7jqx).

The earlier change wrapped the description in the human-readable header of
getTestPlan / getSubTestPlan. But each of those tools returns a second
content block
— a raw JSON.stringify(...) dump of the full plan object —
where the description (and other free-text like name) was still emitted
unwrapped. Since the model reads every content block, an injection payload
placed in a shared plan description still reached it verbatim, so the vector
was not fully closed.

Verified by running the real tools with a payload description: the header was
wrapped, but the JSON block returned the raw payload.

Change

  • Wrap the JSON dump with wrapUntrusted(...) in both get-testplan.ts and
    get-sub-testplan.ts, so untrusted backend content is framed as data in
    every content block.
  • Add tests/tools/tm-desc-wrap.test.ts — exercises the real functions
    (existing suite mocks them) and asserts the payload never appears outside an
    UNTRUSTED wrapper in any block.

Test

  • tsc, eslint: clean
  • tests/tools/tm-desc-wrap.test.ts: 2 passing
  • tests/tools/testmanagement.test.ts: 75 passing (unchanged)

🤖 Generated with Claude Code

The earlier fix wrapped the description in the human-readable header of
getTestPlan / getSubTestPlan, but the same response also emits a second
content block — a raw JSON dump of the full plan object — where the
description (and other free-text fields) were returned UNWRAPPED. An
injection payload in a shared plan description therefore still reached the
model verbatim via that block.

Wrap the JSON dump with wrapUntrusted as well, so untrusted plan content is
framed as data in every content block. Adds a test asserting the payload
never appears outside an UNTRUSTED wrapper. Ref: GHSA-9w6g-vr6g-7jqx.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited), Workspace UI (inherited)

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 3eb8a6e8-1b95-4e6d-b39b-dc50b7f831da

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@gaurav-singh-9227
gaurav-singh-9227 merged commit 4017745 into browserstack:main Sep 25, 2026
2 checks passed
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