Skip to main content

Free 30-min security demo Book Now

Application Security

Juice Shop file-434 Challenge: Full Solution

Solve the Juice Shop file-434 challenge step by step: access acquisitions.md, bypass the 403 with null byte injection, and understand CWE-552 file exposure.

Offensive360 Security Research Team — min read
OWASP Juice Shop juice shop challenges juice shop solutions juice shop file challenge file-434 juice shop sensitive data exposure juice shop ftp juice shop walkthrough juice shop path traversal juice shop null byte owasp juice shop vulnerable web application security testing practice web application security juice shop scoreboard

The file-434 challenge in OWASP Juice Shop is a Sensitive Data Exposure challenge that appears prominently in search results for Juice Shop learners. It requires you to locate and download a confidential file from the application’s FTP directory — bypassing the server-side restriction that blocks direct access. This guide covers the exact steps, the underlying vulnerability class, and what this teaches about real-world file access control weaknesses.


What Is the file-434 Challenge?

In the OWASP Juice Shop scoreboard, the challenge labelled around file access and sensitive data exposure (sometimes surfaced in search results as “file-434”, referring to the challenge’s internal ID or a specific 403 response you encounter) falls into the Sensitive Data Exposure category.

The challenge objective is:

“Access a confidential document.”

The target file is acquisitions.md — a fictional business document stored in Juice Shop’s /ftp/ directory that should require authentication to access, but is accessible due to misconfigured file storage.

Difficulty: ⭐ (1 star — Beginner)

Category: Sensitive Data Exposure

Vulnerability class: Insecure File Storage / Information Disclosure (CWE-552 / CWE-538)

Start your local Juice Shop instance before following this walkthrough:

docker run --rm -p 3000:3000 bkimminich/juice-shop

Step 1: Discover the FTP Directory

Juice Shop’s confidential file is stored in an exposed FTP directory. To find it:

  1. Navigate to the About page: http://localhost:3000/#/about
  2. Scroll to the bottom — there is a link referencing “legal.md”
  3. Hover over or inspect the link. The URL points to:
    http://localhost:3000/ftp/legal.md
  4. The presence of /ftp/ in this link reveals that the application stores files in a directory named ftp.

Alternatively, you can navigate directly to http://localhost:3000/ftp/ — the directory listing is enabled, revealing all files stored there.

What You’ll Find in the FTP Directory

Navigating to http://localhost:3000/ftp/ shows a directory listing:

acquisitions.md        [Confidential — access blocked]
coupons_2013.md.bak    [Backup file — accessible]
eastere.gg             [Easter egg]
incident-support.kdbx  [KeePass database]
legal.md               [Accessible]
package.json.bak       [Backup — access blocked]
quarantine/            [Subdirectory]
suspicious_errors.yml  [Accessible]

The fact that this directory listing is publicly accessible is itself a security finding. In a production application, the /ftp/ directory (or equivalent storage) should not be web-accessible without authentication, and directory listing should be disabled.


Step 2: Attempt Direct Download (You Get a 403)

Try to download acquisitions.md directly:

http://localhost:3000/ftp/acquisitions.md

The server returns:

HTTP/1.1 403 Forbidden
{
  "error": "Only .md and .pdf files can be accessed through this endpoint"
}

This is the restriction. The server allows .md and .pdf files but blocks acquisitions.md. Wait — .md is an allowed extension. The block is specifically on certain filenames, not just extensions.

For the basic 1-star challenge, acquisitions.md is actually directly accessible at http://localhost:3000/ftp/acquisitions.md. If you are getting a 403, you may be looking at a different, related challenge (the Forgotten Developer Backup challenge, which targets package.json.bak).


Step 3: Download the Confidential Document

For the “Access a confidential document” (1-star) challenge:

  1. Navigate directly to:
    http://localhost:3000/ftp/acquisitions.md
  2. The file downloads or displays in the browser
  3. Juice Shop’s notification system shows: “You successfully solved a challenge: Access a confidential document”

The challenge is solved. The scoreboard updates to mark it complete.


The query “file-434” in search engines often refers to a separate but closely related Juice Shop challenge involving a backup file that genuinely returns a 403 error and requires exploitation to download. This is the “Forgotten Developer Backup” challenge (3 stars).

The target is package.json.bak — which is blocked by the extension filter:

http://localhost:3000/ftp/package.json.bak
→ HTTP/1.1 403 Forbidden: Only .md and .pdf files can be accessed

How to Bypass the 403 with Null Byte Injection

The server filters file extensions, blocking .bak files. However, the extension check is vulnerable to a null byte injection attack:

http://localhost:3000/ftp/package.json.bak%2500.md

What’s happening here:

  • %25 is the URL-encoded form of %
  • %2500 double-decodes to %00 — the null byte character
  • The server’s extension validation sees package.json.bak%00.md and reads the extension as .md (allowed)
  • But the operating system and file-serving layer truncate the filename at the null byte: package.json.bak
  • The file is served successfully

Step-by-step:

  1. Navigate to:
    http://localhost:3000/ftp/package.json.bak%2500.md
  2. The server validates .md (the part after the null byte), then serves package.json.bak (the part before the null byte)
  3. The file downloads, revealing Juice Shop’s internal package.json backup
  4. The challenge notification confirms: “You successfully solved a challenge: Forgotten Developer Backup”

Why This Vulnerability Matters

Insecure File Storage (CWE-552 / CWE-538)

The core issue is that Juice Shop stores sensitive files (acquisitions.md, package.json.bak) in a web-accessible directory with no authentication requirement. This represents:

  • CWE-552 — Files or Directories Accessible to External Parties
  • CWE-538 — Insertion of Sensitive Information into Externally-Accessible File or Directory

In production applications, this pattern appears as:

  • Backup files (.bak, .old, .orig) left in web-accessible directories
  • Log files stored in document roots
  • Configuration files (.env, web.config, appsettings.json) accessible via the web server
  • Database dumps or export files in publicly accessible storage buckets

The fix: Store sensitive files outside the web root, behind authentication, or in object storage with proper access controls (private S3 bucket, Azure Blob with SAS tokens, etc.).

Directory Listing Enabled

The /ftp/ directory exposes all its contents because the web server has directory listing enabled. This is a common misconfiguration that turns a simple file access into a full inventory of everything stored in that location.

The fix: Disable directory listing in your web server configuration:

# Nginx — disable directory listing
location /files/ {
    autoindex off;  # Default is off, but make it explicit
}
# Apache — disable directory listing
Options -Indexes
// Express.js — do not serve static directories with autoIndex
app.use('/uploads', express.static('uploads', {
    index: false  // Prevents directory listing
}));

Null Byte Injection (CWE-626)

The null byte bypass (%2500.md) exploits a difference between how the application-level code and the operating system handle filenames. This is:

  • CWE-626 — Null Byte Interaction Error

In modern languages and frameworks (Node.js v6+, Python 3, PHP 7+), null bytes in file paths throw exceptions rather than being silently truncated. Juice Shop is intentionally vulnerable — but in legacy applications (older PHP, Perl CGI scripts), null byte injection was a reliable technique for bypassing extension filters.

The fix in modern code: Validate that the resolved file path contains no null bytes, and use allowlist-based filename validation:

// Express.js — safe file serving with allowlist
const path = require('path');

app.get('/files/:filename', (req, res) => {
    const filename = req.params.filename;
    
    // Allowlist: only allow specific characters in filenames
    if (!/^[a-zA-Z0-9_\-]+\.(pdf|md)$/.test(filename)) {
        return res.status(403).json({ error: 'Invalid filename' });
    }
    
    // Resolve path and verify it stays within the upload directory
    const uploadDir = path.resolve('./uploads');
    const filePath = path.resolve(uploadDir, filename);
    
    if (!filePath.startsWith(uploadDir)) {
        return res.status(403).json({ error: 'Path traversal detected' });
    }
    
    // Check for null bytes (defense-in-depth)
    if (filename.includes('\x00')) {
        return res.status(400).json({ error: 'Invalid filename' });
    }
    
    res.sendFile(filePath);
});

What DAST Scanners Should Find in Juice Shop’s FTP Directory

These file access issues are detectable by a good DAST scanner:

FindingHow DetectedSeverity
Directory listing at /ftp/GET request to directory URL → 200 with file listingMedium
Sensitive file accessible without authGET acquisitions.md → 200High
Backup file exposedGET package.json.bak → file download (after bypass)High
KeePass database exposedGET incident-support.kdbx → 200Critical

A DAST scanner that finds directory listing and unauthenticated file access demonstrates the core detection capability needed for production application scanning. Null byte injection is harder for automated scanners to detect — it requires testing with encoded null bytes in path parameters.


Connecting to Other Juice Shop Challenges

The FTP directory contains multiple challenges. Once you’ve found it, these related challenges are in the same location:

FileChallengeDifficulty
acquisitions.mdAccess a confidential document
package.json.bakForgotten Developer Backup (null byte bypass)⭐⭐⭐
incident-support.kdbxRetrieve the KeePass database (no bypass needed — it downloads directly)
quarantine/ directoryHidden malware quarantine (find what’s in there)Advanced

Work through these in order — they build on each other and collectively teach file access control, directory traversal, and extension bypass techniques.


Detecting These Vulnerabilities in Production Code with SAST

If you’re using Juice Shop to benchmark a SAST scanner, look for whether it detects these source-level issues in the Node.js codebase:

Serving files from a directory without authentication middleware:

// Juice Shop — serves /ftp/ directory without auth
app.use('/ftp', serveIndex('ftp', { icons: true }));
app.use('/ftp', express.static('ftp'));

A SAST tool should flag express.static and serveIndex usage for paths that may contain sensitive files — especially when no authentication middleware precedes them in the middleware chain.

Extension-only validation without allowlist:

// Vulnerable pattern — extension check only (bypassable with null byte in some configurations)
if (!file.endsWith('.md') && !file.endsWith('.pdf')) {
    res.status(403).send({ error: 'Only .md and .pdf files can be accessed' });
    return;
}

A SAST tool performing taint analysis would track file from the request through the extension check to the fs.createReadStream(file) call — noting that the validation is an extension check rather than a resolved-path allowlist check.


Summary

ChallengeTargetTechniqueDifficulty
Access a confidential document/ftp/acquisitions.mdDirect URL access
Forgotten Developer Backup/ftp/package.json.bak%2500.mdNull byte injection⭐⭐⭐

The “file-434” identifier connects to the broad Sensitive Data Exposure challenge cluster in OWASP Juice Shop:

  1. Find the /ftp/ directory — via the About page link to legal.md
  2. Browse the directory listing — enabled by default, reveals all stored files
  3. Download acquisitions.md — directly accessible, no bypass needed (1-star challenge)
  4. Download package.json.bak — requires null byte injection in the URL (3-star challenge)

Both challenges demonstrate real vulnerability patterns found in production applications: sensitive files in web-accessible storage, enabled directory listings, and extension-based access control that can be bypassed.

For a full walkthrough of all Juice Shop challenges across every difficulty level, see our complete Juice Shop challenge solutions guide. For information on setting up Juice Shop and its full challenge categories, see the OWASP Juice Shop complete guide.


Offensive360 DAST automatically detects directory listing, unauthenticated file access, and sensitive file exposure during authenticated scanning of web applications. Book a demo — results in minutes.

Offensive360 Security Research Team

Application Security Research

Dynamic testing

Benchmark a real DAST scanner on your lab

Point Offensive360 DAST at Juice Shop, DVWA or your own staging app: headless-browser crawling, 40+ active exploit checks and request/response proof for every finding.

Also see: Free Juice Shop benchmark kit (PDF) · Attack Surface Management · Autonomous Red Teaming

Benchmark a real DAST scanner on your lab

Book a DAST demo