Skip to content

fix: strip antml thinking tags#59550

Merged
obviyus merged 2 commits into
mainfrom
fix/antml-thinking-tags
Apr 2, 2026
Merged

fix: strip antml thinking tags#59550
obviyus merged 2 commits into
mainfrom
fix/antml-thinking-tags

Conversation

@obviyus

@obviyus obviyus commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • strip namespaced antml:thinking tags in the shared reasoning sanitizer
  • cover the new tag shape in shared and embedded assistant-text tests

Testing

  • pnpm test -- src/shared/text/reasoning-tags.test.ts
  • pnpm test -- src/agents/pi-embedded-utils.test.ts -t 'strips reasoning/thinking tag variants'

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS maintainer Maintainer-authored PR labels Apr 2, 2026
@obviyus obviyus self-assigned this Apr 2, 2026
@obviyus
obviyus force-pushed the fix/antml-thinking-tags branch from 9500d38 to b554177 Compare April 2, 2026 08:58
@obviyus
obviyus merged commit c27b45f into main Apr 2, 2026
9 checks passed
@obviyus
obviyus deleted the fix/antml-thinking-tags branch April 2, 2026 08:58
@aisle-research-bot

aisle-research-bot Bot commented Apr 2, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Namespaced antml:final wrapper bypasses reasoning-tag stripping (information disclosure)
1. 🟡 Namespaced wrapper bypasses reasoning-tag stripping (information disclosure)
Property Value
Severity Medium
CWE CWE-200
Location src/shared/text/reasoning-tags.ts:5-8

Description

stripReasoningTagsFromText relies on a fast-path regex (QUICK_TAG_RE) to decide whether to do any stripping at all, and then uses FINAL_TAG_RE/THINKING_TAG_RE to remove wrappers.

After the change, namespaced thinking tags like <antml:thinking> are detected/stripped, but namespaced final tags are not:

  • QUICK_TAG_RE only allows the optional antml: prefix for thinking tags, not for final
  • FINAL_TAG_RE only matches <final ...> (and </final>), not <antml:final ...>

As a result, content wrapped in <antml:final> ... </antml:final> will not be detected by QUICK_TAG_RE and the function returns the original text unmodified, potentially leaking content that should be stripped or unwrapped (depending on caller expectations).

Vulnerable behavior example:

  • input: <antml:final>SECRET</antml:final>
  • output: <antml:final>SECRET</antml:final> (no stripping performed)

Vulnerable code:

const QUICK_TAG_RE = /<\s*\/?\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking|final)\b/i;
const FINAL_TAG_RE = /<\s*\/?\s*final\b[^<>]*>/gi;

Recommendation

Treat final consistently with thinking tags by allowing the optional namespace prefix in both the fast-path and stripping regex.

For example:

const QUICK_TAG_RE =/<\s*\/?\s*(?:(?:antml:)?(?:think(?:ing)?|thought|final)|antthinking)\b/i;

const FINAL_TAG_RE = /<\s*\/?\s*(?:antml:)?final\b[^<>]*>/gi;

Also add tests to ensure <antml:final> is detected and stripped/handled as intended.


Analyzed PR: #59550 at commit b554177

Last updated on: 2026-04-02T09:04:03Z

@obviyus

obviyus commented Apr 2, 2026

Copy link
Copy Markdown
Contributor Author

Landed in c27b45f

@greptile-apps

greptile-apps Bot commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extends the shared reasoning-tag sanitizer to recognise Anthropic's namespace-prefixed antml:thinking (and related antml:think / antml:thought) variants, preventing those internal-monologue tags from leaking into user-visible replies. The regex changes are minimal and targeted, and matching test coverage is added in both reasoning-tags.test.ts and pi-embedded-utils.test.ts. The CHANGELOG.md change also cleans up leftover git conflict markers from a previous merge that had landed unresolved conflict lines in the file (the Exec approvals/config entry removed from the conflict region is already present earlier in the file at line 30, so no changelog content is lost).

Key changes:

  • QUICK_TAG_RE and THINKING_TAG_RE are updated with an optional (?:antml:)? prefix so <thinking>, <think>, and <thought> are stripped alongside their non-namespaced counterparts
  • New test cases in the shared sanitizer suite and the embedded-utils suite exercise the new tag shape
  • Merge conflict artefacts in CHANGELOG.md are removed; the displaced duplicate changelog entry was already present in the ## Unreleased section

Confidence Score: 5/5

  • Safe to merge — the change is a narrow, well-tested regex extension with no impact on existing behaviour
  • The regex modification is correct: \b is placed after the full tag-name group (including the optional antml: prefix), so word-boundary detection remains accurate. Closing tags are captured correctly via match[1]. The QUICK_TAG_RE fast-path correctly detects namespaced tags so the heavier THINKING_TAG_RE only runs when needed. All removed CHANGELOG content is either duplicate or unwanted conflict-marker noise. The only minor note is that final is not given the same antml: treatment, but no such tag is known to be emitted today.
  • No files require special attention
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/shared/text/reasoning-tags.ts
Line: 5-8

Comment:
**`final` tag missing `antml:` variant in `THINKING_TAG_RE`**

`QUICK_TAG_RE` still includes `final` in its optional-namespace group, but `THINKING_TAG_RE` (and `FINAL_TAG_RE`) do not have a corresponding `antml:final` variant. If Anthropic ever emits `<final>…</final>`, `QUICK_TAG_RE` would fire but `FINAL_TAG_RE` and `THINKING_TAG_RE` would both miss it, and the tag would leak through. This is a minor consistency nit rather than a current crash, but worth noting if the same namespace treatment needs to be applied uniformly.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix: strip antml thinking tags (#59550)" | Re-trigger Greptile

Comment on lines +5 to +8
const QUICK_TAG_RE = /<\s*\/?\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking|final)\b/i;
const FINAL_TAG_RE = /<\s*\/?\s*final\b[^<>]*>/gi;
const THINKING_TAG_RE = /<\s*(\/?)\s*(?:think(?:ing)?|thought|antthinking)\b[^<>]*>/gi;
const THINKING_TAG_RE =
/<\s*(\/?)\s*(?:(?:antml:)?(?:think(?:ing)?|thought)|antthinking)\b[^<>]*>/gi;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 final tag missing antml: variant in THINKING_TAG_RE

QUICK_TAG_RE still includes final in its optional-namespace group, but THINKING_TAG_RE (and FINAL_TAG_RE) do not have a corresponding antml:final variant. If Anthropic ever emits <final>…</final>, QUICK_TAG_RE would fire but FINAL_TAG_RE and THINKING_TAG_RE would both miss it, and the tag would leak through. This is a minor consistency nit rather than a current crash, but worth noting if the same namespace treatment needs to be applied uniformly.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/shared/text/reasoning-tags.ts
Line: 5-8

Comment:
**`final` tag missing `antml:` variant in `THINKING_TAG_RE`**

`QUICK_TAG_RE` still includes `final` in its optional-namespace group, but `THINKING_TAG_RE` (and `FINAL_TAG_RE`) do not have a corresponding `antml:final` variant. If Anthropic ever emits `<final>…</final>`, `QUICK_TAG_RE` would fire but `FINAL_TAG_RE` and `THINKING_TAG_RE` would both miss it, and the tag would leak through. This is a minor consistency nit rather than a current crash, but worth noting if the same namespace treatment needs to be applied uniformly.

How can I resolve this? If you propose a fix, please make it concise.

ngutman pushed a commit that referenced this pull request Apr 3, 2026
steipete pushed a commit to duncanita/openclaw that referenced this pull request Apr 4, 2026
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
Nachx639 pushed a commit to Nachx639/clawdbot that referenced this pull request Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant