Skip to content

fix(security): remove deep-research search/fetch tools (GHSA-j7p8-g5m6-3wv5) - #162

Merged
nictuku merged 1 commit into
mainfrom
fix/ghsa-j7p8-g5m6-3wv5
Sep 22, 2026
Merged

nictuku merged 1 commit into
mainfrom
fix/ghsa-j7p8-g5m6-3wv5

Conversation

@nictuku

@nictuku nictuku commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Fixes GHSA-j7p8-g5m6-3wv5, reported by @BarakSrour.

The bug

openai_deep_research.py cached Meta Ads records in a module-level MetaAdsDataManager singleton keyed only by "<type>:<id>" — no caller, session or tenant component, no eviction. search wrote to it under the calling user's credential; fetch read it back with no credential resolution and no ownership check. Under --transport streamable-http, where one process serves every caller, any caller holding a syntactically-valid bearer token could read another caller's cached ad-account, campaign, ad, page and business records — name, currency, total spend, balance, and the raw Graph objects. fetch never calls Graph, so nothing downstream validated the reader's token either.

Why removal instead of scoping the cache

Production traffic over the last 7 days: 178 fetch calls from 72 users, 0 of them successful. 124 returned "Record not found"; the rest were schema-validation errors from clients passing url / path / params, i.e. treating fetch as a generic Graph fetcher. The hosted MCP already filters the Python search out of tools/list and substitutes its own implementation, so the cache it fed was never populated there.

There was no working behaviour left to preserve. Per-caller cache keys would have kept the machinery, the memory growth and the next version of this bug for a tool nobody successfully uses.

Changes

  • Delete meta_ads_mcp/core/openai_deep_research.py and its registration in core/__init__.py and core/server.py.
  • Delete the three test files that existed only to exercise those tools (test_integration_openai_mcp.py, test_openai_mcp_deep_research.py, test_account_search.py — the latter two are manual scripts against a local server).
  • New tests/test_deep_research_tools_removed.py: asserts the module is unimportable, that search/fetch are not registered MCP tools, and that neighbouring tools survived.
  • README.md: drop the mcp_meta_ads_search entry.
  • Bump to 1.0.122 and add the advisory to SECURITY.md.

Client impact

Callers that used the deep-research pair should use the typed tools: get_ad_accounts, get_campaigns, get_campaign_details, get_adsets, get_ads, get_ad_details. Hosted users are unaffected — the hosted search is the Next.js implementation and stays.

Full suite: 545 passed, 9 skipped.

…6-3wv5)

The openai_deep_research module cached Meta Ads records in a module-level singleton keyed only by "<type>:<id>". Under streamable-http one process serves every caller, and fetch read that cache with no credential resolution and no ownership check, so any caller could read another caller's cached account, campaign, ad, page and business records.

Removed rather than scoped: in production every fetch call already failed (70% "Record not found", the rest schema-validation errors from clients treating it as a generic Graph fetch), and the hosted MCP replaces search with its own implementation, so there was no working behaviour to preserve. Regression tests assert neither tool is registered again.

Also bumps to 1.0.122 and documents the advisory in SECURITY.md.
@nictuku
nictuku force-pushed the fix/ghsa-j7p8-g5m6-3wv5 branch from fce7047 to fb14394 Compare September 22, 2026 15:58
@nictuku
nictuku merged commit 96eaf2d into main Sep 22, 2026
4 checks passed
@nictuku
nictuku deleted the fix/ghsa-j7p8-g5m6-3wv5 branch September 22, 2026 19:04
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.

1 participant