🧯 The Staff Safety Desk

Tuesday, May 12, 2026

8 stories

Generated with AI from public sources. Verify before relying on for decisions.

🎧 Listen to this briefing or subscribe as a podcast →

Today on the desk: a self-propagating npm/PyPI worm that shipped malware with valid SLSA provenance, fresh CVEs in urllib3 and PgBouncer, a German BSI advisory on Django, and more data confirming that AI-assisted code is fast to write and slow to review. The connecting thread is the gap between 'attestation passed' and 'actually safe'.

Supply Chain & GitHub Actions

Mini Shai-Hulud worm hits 170+ npm and PyPI packages with valid SLSA provenance

On May 11, attackers chained a pull_request_target cache-poisoning bug with in-memory OIDC token extraction to publish 84 malicious @tanstack versions in six minutes, then self-propagated to 170+ npm and PyPI packages including Mistral AI, UiPath, OpenSearch, and guardrails-ai β€” all carrying valid SLSA Build Level 3 attestations. The payload harvests AWS/GCP/Vault/K8s creds and Claude/Cursor config files, persists via .claude/ and .vscode/ hooks, exfiltrates over Session P2P, and arms a dead-man's switch that runs rm -rf $HOME if the stolen GitHub token gets revoked within 24 hours. ELI15: the build robot's badge of authenticity got stamped on a poisoned package β€” the stamp is real, the contents are not.

If your CI publishes via OIDC trusted publishing on pull_request_target, you are running the exact pattern this worm exploits β€” pin actions to commit SHAs, kill pull_request_target on any workflow with publish scope, and disarm the watchdog before rotating tokens.

Verified across 8 sources: Snyk · Socket · TanStack Postmortem · Upwind Security · The Hacker News · DevOps Daily · GitHub Advisory (CVE-2026-45321) · mistralai/client-python #523

Django & Python Ecosystem

urllib3 ships two CVEs and PgBouncer 1.25.2 patches four SCRAM bugs β€” patch your transitive deps

urllib3 disclosed CVE-2026-44431 (low-level ProxyManager forwarding Authorization/Cookie/Proxy-Authorization headers across origins on redirects when assert_same_host=False) and CVE-2026-44432 (decompression-bomb safeguards bypassed in the streaming response path, memory-exhaustion DoS). Both reach you transitively through requests, boto3, and pip. Separately, PgBouncer 1.25.2 fixes four remote-exploitable SCRAM authentication bugs triggered by malformed packets plus an admin-console command that let unauthenticated callers terminate sessions.

For a Django + Postgres + S3 stack: you almost certainly have urllib3 pinned through boto3 and pip, and if you run PgBouncer in front of Postgres, the SCRAM crash path is reachable from anything that can reach the pooler port β€” audit your lockfile and roll the pooler now.

Verified across 3 sources: GitLab Advisories (CVE-2026-44431) · TechJack (GHSA-mf9v-mfxr-j63j) · Warp2Search (PgBouncer 1.25.2)

BSI flags three Django CVEs (5.3 medium) β€” Django <6.0.5 and <5.2.14 affected

Germany's BSI issued an advisory on May 5 covering CVE-2026-35192, CVE-2026-5766, and CVE-2026-6907 against Django <6.0.5 and <5.2.14, all rated CVSS 5.3 with remote attackers able to disclose information or trigger DoS. Three distinct CVEs in one advisory suggests three different flaw classes rather than one root cause β€” read the Django security release notes before patching to understand which surfaces (URL parsing, form handling, etc.) you actually expose.

Direct hit on the framework your portal runs on β€” verdict: patch to 6.0.5 / 5.2.14 on the next maintenance window unless you can confirm none of the three CVE classes touch your views.

Verified across 1 sources: News.de (BSI advisory)

Real-world XSS via Django mark_safe() on f-strings β€” and a Semgrep rule to catch it

A writeup walks through a reflected XSS where a developer wrapped mark_safe() around an f-string interpolating untrusted query params, bypassing autoescape and leading to session theft when SESSION_COOKIE_HTTPONLY was disabled. The fix is the standard one β€” format_html() escapes arguments while preserving template structure β€” and the post ships a copy-pasteable Semgrep rule plus test patterns for CI. ELI15: mark_safe() tells Django 'trust me, I've already cleaned this' β€” wrapping it around an f-string with user input is lying to the framework on the user's behalf.

Drop the Semgrep rule into your supply-chain pipeline now β€” mark_safe(f"...") is a near-perfect AI-slop signature because LLMs love f-strings and reach for mark_safe when Django escapes their HTML.

Verified across 1 sources: Dev.to (Security Stefan)

AI Slop & Review Patterns

Every AI agent failure in 2026 is an idempotency problem

Two independent writeups this week catalog the same pattern across five production incidents β€” 14-email retry storms, duplicate Stripe charges, triplicated orders, oversold inventory, cascading support tickets β€” all caused by non-idempotent tool calls colliding with at-least-once retries from agent frameworks, webhooks, and brokers. Tool-call volume in agent traces jumped from 0.5% to 21.9% in a year, a 44x expansion of the retry surface, and the fix is the boring 25-year-old one: idempotency keys in tool contracts, deterministic key synthesis, and a dedup store at the boundary. ELI15: if you tell a forgetful robot to 'press the charge button' and it can't remember whether it already pressed it, it presses again β€” give it a sticky note with the order ID and a 'done' list.

This is the single highest-yield review heuristic for AI-generated diffs touching external I/O: if the new code calls Stripe, DocuSeal, Coinbase Commerce, or any webhook handler without a deterministic idempotency key and a dedup store, the PR is wrong regardless of whether tests pass.

Verified across 2 sources: Dev.to (Schuchardt) · Conzit

AI-Assisted Coding Practice

Cursor May changelog: Bugbot effort levels, parallel agents, admin model blocklists (June 1 deadline)

Cursor's May release ships customizable Bugbot review effort levels with published catch rates (0.7 bugs/run default, 0.95 at high effort; 79% resolved at merge), parallel async subagents that can split a plan file across worktrees, Teams integration for cloud agents, and granular model/provider blocklists for admins with a June 1 migration deadline. Stability fixes hit MCP auth, terminal interaction, and cloud agent hydration.

The Bugbot numbers are the first vendor-published catch-rate data tied to effort tiers, which gives you something concrete to A/B against your own review process β€” and the admin blocklist migration is a hard date if your team has any model-access governance.

Verified across 1 sources: Cursor Changelog

The review bottleneck: AI-generated PRs wait 4.6x longer and merge at 32.7%

LinearB's analysis of 8.1M PRs found AI-generated code waits 4.6x longer for review than human code and merges only 32.7% of the time, versus 84.4% for manual PRs β€” code writing is 16% of dev time, so 'faster generation' just moves the constraint to review. A separate MERT randomized trial of 16 experienced devs across 246 tasks measured a 19% slowdown when using AI in familiar codebases, against a self-reported 24% speedup (a 43-point perception gap).

If you're tracking PR throughput as your AI-productivity metric, you're measuring the wrong thing β€” the rework ratio and 30-day post-merge bug rate are the only numbers that distinguish 'AI saves time' from 'AI moves work into review and incident response'.

Verified across 3 sources: Dev.to (code-board) · ByteIota (MERT trial) · Dev.to (Gomes β€” measuring velocity)

Web App Security

Three fresh SSRF CVEs (Gotenberg, FireFighter, Budibase) β€” same allowlist failure pattern

Three SSRF CVEs landed this week with the same underlying shape: Gotenberg's Chromium URL-to-PDF endpoint only blocks file:// and follows 302 redirects without re-validation; FireFighter's /api/v2/firefighter/raid/jira_bot is unauthenticated (permission_classes=[AllowAny]) and fetches arbitrary URLs, hitting CVSS 9.9 by stealing AWS IMDS credentials; Budibase's plugin URL allowlist is bypassed by a trivial .tar.gz substring injection. All three share the same root cause β€” no consistent default-deny on RFC 1918, 169.254.0.0/16, 127.0.0.0/8 β€” and the same fix shape: re-check the boundary on every fetcher, including redirect targets.

If your portal generates PDFs server-side, accepts file URLs, or proxies any user-supplied link, the review heuristic is: deny-list internal ranges by default, re-validate after every redirect, and never default any endpoint that fetches URLs to AllowAny.

Verified across 3 sources: GitLab Advisories (Gotenberg CVE-2026-42595) · The Hacker Wire (FireFighter CVE-2026-42864) · GitLab Advisories (Budibase CVE-2026-45061)


The Big Picture

Valid attestation is not safety The TanStack/Mistral worm shipped with valid SLSA Build Level 3 provenance and OIDC-bound npm publishing. Provenance certifies the build pipeline, not the cleanliness of the code that pipeline built. Signature-only verification is now a known-bypassable control.

Idempotency is the single biggest AI-slop pattern Two independent writeups today blame nearly every production AI-agent incident β€” duplicate charges, ghost orders, 14-email retry storms β€” on non-idempotent tool calls colliding with at-least-once retry semantics. The same lesson applies to webhook handlers, transaction.on_commit callbacks, and any external I/O wrapped in retries.

The review bottleneck has moved, not shrunk LinearB data on 8.1M PRs shows AI-generated code waits 4.6x longer for review and merges at 32.7% vs 84.4% for human PRs. Combined with the MERT randomized trial (experienced devs 19% slower with AI), the velocity story keeps inverting once you measure rework instead of throughput.

What to Expect

2026-05-14 CoW DAO CIP-86 reimbursement claims deadline (DNS-hijack victims)
2026-05-15 Arbitrum DAO vote opens on $71M rsETH ETH transfer to Aave LLC custody
2026-05-15 Arbitrum OAT June 2026 election applications open (through June 5)
2026-06-01 Cursor admin model/provider blocklist migration deadline
2026-06-25 Arbitrum OAT committee voting window opens (through July 2)

β€” The Staff Safety Desk

πŸŽ™ Listen as a podcast

Subscribe in your favorite podcast app to get each new briefing delivered automatically as audio.

Apple Podcasts
Library tab β†’ β€’β€’β€’ menu β†’ Follow a Show by URL β†’ paste
Overcast
+ button β†’ Add URL β†’ paste
Pocket Casts
Search bar β†’ paste URL
Castro, AntennaPod, Podcast Addict, Castbox, Podverse, Fountain
Look for Add by URL or paste into search

Spotify isn’t supported yet β€” it only lists shows from its own directory. Let us know if you need it there.