Skip to content

fix(adapters): keep tool-call ID reminting linear (prevent quadratic DoS) - #661

Closed
luvs01 wants to merge 2 commits into
devfrom
codex/propose-fix-for-tool-call-id-reminting-vulnerability
Closed

luvs01 wants to merge 2 commits into
devfrom
codex/propose-fix-for-tool-call-id-reminting-vulnerability

Conversation

@luvs01

@luvs01 luvs01 commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Motivation

  • A malicious or compromised openai-chat upstream could emit many duplicate tool-call IDs and cause the reminter to restart suffix enumeration at -2 for each duplicate, producing O(N²) Set.has probes and stalling the event loop.
  • The change ensures collision-search progress is preserved per post-truncation candidate prefix (the collision domain that actually determines generated suffixes), so high-cardinality duplicate responses cannot monopolize CPU and block unrelated requests.

Description

  • Make createToolCallIdReminter resume suffix search per truncated collision domain by keying nextSuffixByBase: Map<string, number> on base.slice(0, MAX_TOOL_CALL_ID_LENGTH - 2) — the post-truncation prefix that determines the candidate sequence — and updating it when a candidate is chosen in src/adapters/openai-chat/tool-call-id-remint.ts.
  • Add a focused regression test that issues 10,000 repeated rawId remints and asserts the number of Set.prototype.has probes stays bounded, in tests/adapters/openai/openai-chat-tool-call-id-remint.test.ts.
  • Document the improved collision-search contract (linear probes per collision domain) in structure/providers-and-adapters.md.

Testing

  • Ran bun test tests/adapters/openai/openai-chat-tool-call-id-remint.test.ts, which passed (14 passed, 0 failed).
  • Ran bun run typecheck, which succeeded.
  • Ran bun run structure:check and bun run privacy:scan, both of which succeeded.
  • bun run test:changed could not be executed in this checkout because the comparison ref (dev/remote) is not available; other focused validation above was performed instead.

Codex Task


Devin Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-27T12:28:20.944914Z ccfb8e6 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Sep 27, 2026
@coderabbitai

coderabbitai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository: luvs01/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 7553c351-c1f5-45ae-9cc6-422a93cce8bf


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

devin-ai-integration[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

Devin Review

Comment thread src/adapters/openai-chat/tool-call-id-remint.ts
@devin-ai-integration

Copy link
Copy Markdown

Resolved — PR description corrected.

luvs01 and others added 2 commits September 27, 2026 21:20
The suffix cursor was keyed by the full sanitized base, but a candidate
keeps at most MAX_TOOL_CALL_ID_LENGTH - 2 characters of it — longer
suffixes only truncate deeper. Distinct ids agreeing on that prefix
therefore produce the same candidate sequence while each restarting the
search at -2, so M prefix-sharing ids emitted twice still cost ~M^2/2
occupied-set probes.

Key the cursor by the post-truncation prefix — the actual collision
domain — so all ids sharing it resume the same search. The occupied-set
check still decides acceptance, keeping emitted ids unique and within
the 64-char bound.

Regression test: 1,000 conforming 64-char ids plus 500 overlength
non-conforming ids, all sharing the first 62 characters and each
emitted twice, stay under 10k probes (was ~1.13M before).

Co-Authored-By: Epinephrine <luvs01@hanmail.net>
@luvs01
luvs01 force-pushed the codex/propose-fix-for-tool-call-id-reminting-vulnerability branch from 0b09686 to ccfb8e6 Compare September 27, 2026 12:25
@luvs01

luvs01 commented Sep 27, 2026

Copy link
Copy Markdown
Owner Author

이관됨: lidge-jun#6083

@luvs01

luvs01 commented Sep 27, 2026

Copy link
Copy Markdown
Owner Author

현재 dev 기준 리베이스 후 상류 제출 완료. 포크 PR 목적 달성으로 종료.

@luvs01 luvs01 closed this Sep 27, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ccfb8e63e1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// prefix is the collision domain. The resume cursor has to live on the domain, not the full
// base: distinct ids sharing it would otherwise each restart at -2 and re-run every probe an
// earlier base already made, which is quadratic in the number of such ids.
const prefix = base.slice(0, MAX_TOOL_CALL_ID_LENGTH - 2);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Track progress after every truncation boundary

Fresh evidence beyond the earlier report is the next suffix-width boundary: IDs that share only the first 60 characters have different 62-character map keys here, but once n >= 100, line 40 truncates every candidate to those same 60 characters. Each domain therefore re-probes the candidates occupied by earlier domains; for example, 1,024 distinct 62-character IDs with a common 60-character prefix, each repeated 100 times, cause about 94.7 million Set.has probes for roughly 103,000 calls. Thus an attacker-controlled response remains quadratic despite the documented linear contract. Coordinate progress by the prefix retained at each suffix width, or add a fixed base discriminator so candidate sequences cannot converge.

AGENTS.md reference: structure/AGENTS.md:L9-L10

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

aardvark bug Something isn't working codex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant