Pentest OWASP Juice Shop
Exploit real web vulnerabilities and write a professional pentest report.
Introduction
30 Second Summary
Every day, attackers exploit vulnerabilities in web applications to steal data, hijack accounts, and disrupt businesses. Security professionals use the exact same techniques to find these weaknesses first, fix them, and protect users.
In this project, you will conduct a full penetration test against OWASP Juice Shop, a deliberately vulnerable modern web application. You will exploit real-world vulnerabilities and document your findings in a professional report.
What You'll Build
A complete penetration testing engagement using Kali Linux, Burp Suite, and Nmap against OWASP Juice Shop running in Docker.
By the end of this project, you'll have:
- A fully configured pentest lab with Docker, Juice Shop, and a Burp Suite proxy chain intercepting all traffic to your target.
- Documented exploitation of 6+ vulnerabilities across SQL Injection, Cross-Site Scripting, Broken Access Control, IDOR, and Security Misconfiguration categories.
- A professional penetration testing report with severity ratings, evidence screenshots, and remediation recommendations ready for your cybersecurity portfolio.
- Secret Mission: Manipulate JSON Web Tokens to attempt privilege escalation or forge a discount coupon.
Are there any prerequisites?
This project assumes you have Kali Linux running in VirtualBox on Windows 11. You should also have basic familiarity with terminal commands and Burp Suite proxy interception from prior experience with DVWA.
Set Up the Pentest Lab
Every professional penetration test starts with building a controlled lab environment. Your lab needs three things: a target application to attack, a proxy to intercept traffic, and a scanner to map the network.
In this step, you will install Docker inside your Kali VM, deploy OWASP Juice Shop as your target, configure Burp Suite to intercept all browser traffic, and run an Nmap scan to document the target from a network perspective.
In this step, get ready to:
- Install Docker and deploy OWASP Juice Shop as your penetration testing target.
- Configure Firefox to proxy all traffic through Burp Suite and install Burp's CA certificate.
- Run Nmap reconnaissance against the target to document the attack surface.
Install Docker and deploy Juice Shop
Docker lets you run pre-built applications inside isolated containers. OWASP Juice Shop ships as a Docker image, so you can deploy the entire vulnerable web application with a single command.
- Open a terminal in your Kali VM by right-clicking the desktop and selecting Open Terminal Here.
- Install Docker by running this command:
sudo apt install -y docker.io
Why docker.io and not docker?
On Kali Linux, the package named docker is actually an unrelated window manager docking application. The real Docker engine is packaged as docker.io. This is a common source of confusion for beginners on Kali.
- Enable and start the Docker service by running:
sudo systemctl enable docker --now
- Pull the OWASP Juice Shop Docker image by running:
sudo docker pull bkimminich/juice-shop
What is OWASP Juice Shop?
OWASP Juice Shop is probably the most modern and sophisticated insecure web application available for security training. It is built with Angular, Node.js, and Express, simulating a realistic e-commerce site with dozens of intentional vulnerabilities.
Unlike DVWA's isolated exercise pages, Juice Shop presents a full single-page application where vulnerabilities are hidden in realistic workflows. This makes it much closer to what you would encounter during a real penetration test engagement.
- Launch the Juice Shop container in detached mode by running:
sudo docker run -d -p 3000:3000 bkimminich/juice-shop
What does this command do?
- -d runs the container in the background so you can keep using the terminal.
- -p 3000:3000 maps port 3000 inside the container to port 3000 on your Kali VM.
- bkimminich/juice-shop is the official Juice Shop image maintained by the OWASP project.
- Wait about 10-15 seconds for the application to start up, then open Firefox.
- Navigate to http://localhost:3000 in the Firefox address bar.
You should see the Juice Shop storefront with products, a search bar, and a navigation menu.
Seeing a blank page or connection refused?
- The container may still be starting. Wait 30 seconds and refresh the page.
- Run sudo docker ps to confirm the container is running. You should see bkimminich/juice-shop in the list with a status of "Up".
- If the container is not listed, re-run the sudo docker run command above.
Need more help? Help me troubleshoot why my Juice Shop container isn't starting on Kali Linux.
Configure Burp Suite proxy and browser
A proxy sits between your browser and the target application, letting you inspect and modify every HTTP request. Burp Suite is the industry-standard tool for this in penetration testing.
- Open Burp Suite Community Edition from the Kali applications menu by clicking Applications in the top-left corner of the screen.
- Navigate to Web Application Analysis and click burpsuite.
What will Burp Suite ask on launch?
Burp Suite will present a project selection screen. Since the Community Edition does not support saving projects, you will select a temporary project with default settings.
- Select Temporary Project and click Next.
- Keep Use Burp defaults selected and click Start Burp.
Burp Suite opens with its proxy listener already active on 127.0.0.1:8080 by default.
- Now configure Firefox to send all traffic through Burp. Switch to Firefox.
- Click the hamburger menu (three horizontal lines) in the top-right corner of Firefox.
- Click Preferences.
- Scroll down to the Network Settings section and click the Settings button.
- Select Manual proxy configuration.
- In the HTTP Proxy field, enter 127.0.0.1.
- In the Port field, enter 8080.
- Check the box Also use this proxy for HTTPS.
- Delete anything that appears in the No proxy for field.
- Click OK to save your proxy settings.
Firefox now routes all HTTP and HTTPS traffic through Burp Suite. Next, you need to install Burp's CA certificate so Firefox trusts the intercepted HTTPS connections.
- In Firefox, navigate to http://burpsuite in the address bar.
- Click CA Certificate in the top-right corner of the page to download Burp's CA certificate. Note where the file is saved.
- Open Firefox's hamburger menu again and click Preferences.
- Click Privacy & Security in the left sidebar.
- Scroll down to the Certificates section and click View Certificates.
- Go to the Authorities tab and click Import.
- Select the Burp CA certificate file you just downloaded and click Open.
- Check the box Trust this CA to identify websites and click OK.
- Close all certificate dialogs.
- Verify the proxy chain works by navigating to http://localhost:3000 in Firefox.
- Switch to Burp Suite and click the Proxy tab, then click HTTP history.
You should see multiple requests to localhost:3000 listed in the HTTP history. This confirms all Juice Shop traffic is flowing through Burp Suite.
Turn off interception for now
In the Proxy tab, make sure Intercept is off (the button should say "Intercept is off"). When interception is on, Burp holds every request until you manually forward it. For browsing and reconnaissance, you want traffic to flow freely while Burp records it in the background.
Not seeing requests in Burp's HTTP history?
- Double-check your Firefox proxy settings point to 127.0.0.1 port 8080.
- Make sure the No proxy for field in Firefox is completely empty. If localhost is listed there, Firefox will bypass the proxy for Juice Shop traffic.
- Confirm Burp's proxy listener is active. In Burp, go to Proxy > Proxy settings and check that 127.0.0.1:8080 shows as running.
Still stuck? Help me fix my Burp Suite proxy connection with Firefox on Kali Linux.
Run Nmap reconnaissance against the target
Reconnaissance is the first phase of any penetration test methodology. Even on a local target, documenting what services are running establishes the formal scope of your engagement and gives you practice writing the report's methodology section.
- Switch back to your terminal in Kali.
- Run an Nmap service version scan against the Juice Shop port by running:
nmap -sV -p 3000 localhost
What does this command do?
- -sV tells Nmap to probe open ports and determine the service name and version.
- -p 3000 limits the scan to port 3000 only, where Juice Shop is running.
- localhost targets your own machine, where the Docker container is accessible.
You should see output showing port 3000 as open with a Node.js-related service detected. Keep note of this output for the Scope and Methodology section of your penetration testing report later.
Nmap showing port 3000 as closed?
- Make sure the Juice Shop container is still running. Run sudo docker ps to check.
- If the container stopped, restart it with sudo docker run -d -p 3000:3000 bkimminich/juice-shop.
Need help? Help me understand why Nmap shows port 3000 as closed when my Docker container should be running.
Your pentest lab is fully operational. You have a target application running, a proxy intercepting all traffic, and reconnaissance data documenting the attack surface. Next up, you will exploit your first vulnerability by using SQL Injection to bypass Juice Shop's authentication and gain admin access.
Exploit SQL Injection and Authentication Bypass
Your pentest lab is running and capturing traffic. Now it is time to use that lab to demonstrate one of the most dangerous vulnerabilities in web applications.
In this step, you will exploit SQL Injection to bypass authentication entirely, gaining access to the administrator account without knowing the password. You will also extract the database schema to show how attackers escalate from a simple login bypass to full data exfiltration.
In this step, get ready to:
- Bypass login authentication using a SQL Injection payload.
- Access the hidden administration panel and document exposed data.
- Extract the database schema using a UNION SELECT attack in Burp Repeater.
Perform SQL Injection on the login form
Web applications that build database queries by concatenating user input are vulnerable to SQL Injection. An attacker can insert SQL syntax into an input field to change the query's logic entirely.
- In Firefox, click Account in the top-right corner of the Juice Shop homepage.
- Click Login.
- In the Email field, enter this SQL Injection payload:
' or 1=1--
- In the Password field, type any value (for example, test).
- Click Log in.
You should be logged in as the administrator account (admin@juice-sh.op) without ever providing a valid password.
Why does this work?
The application builds its login query by inserting your email directly into a SQL statement. When you enter ' or 1=1--, the apostrophe closes the application's string. Then or 1=1 makes the entire WHERE clause evaluate to true. Finally, -- comments out the rest of the query, including the password check.
The query returns the first user in the database, which happens to be the administrator. This is why parameterized queries are critical. They treat user input as data, never as executable SQL.
- Switch to Burp Suite and click the Proxy tab.
- Click HTTP history.
- Find the POST request to /rest/user/login in the history list.
- Click on it to view the request and response in the lower pane.
The response should show a 200 status code with an authentication token in the JSON body. This confirms the server accepted your injection payload as valid credentials.
Take a screenshot now
Capture both the login form with your payload entered and the Burp Suite HTTP history showing the successful POST request and response. You will need these for your pentest report later.
Still seeing an error on login?
Make sure you include the leading apostrophe in the payload. The full text is ' or 1=1-- (apostrophe, space, or, space, 1=1, two dashes). If the request does not appear in Burp HTTP history, verify that Firefox is still proxied through 127.0.0.1:8080.
Why isn't my SQL Injection payload working on the Juice Shop login form?
Access the administration panel
Many applications hide admin interfaces by simply not linking to them in the navigation. The routes still exist in the client-side code. This is Broken Access Control: relying on obscurity instead of server-side authorization checks.
- While still logged in as the admin, type the following URL directly into Firefox's address bar:
http://localhost:3000/#/administration
You should see the administration panel with a full list of registered users and their email addresses.
What makes this Broken Access Control?
The admin panel exists at a predictable route but has no server-side check to verify the requesting user actually has admin privileges. Anyone who discovers the URL can access it.
In a real application, the server must validate the user's role on every request to a protected resource. Hiding a route in the client-side code is not a security measure.
- Document the user list displayed on the administration panel. Note the registered emails and any other sensitive data exposed.
- Take a screenshot of the administration panel showing the user list.
Seeing a blank page at the admin route?
Make sure you are still logged in as the admin user from the previous substep. If your session expired, repeat the SQL Injection login. Also verify the URL includes the /#/ prefix. This is a client-side route, not a server path.
Help me access the Juice Shop administration panel after logging in with SQL Injection.
Explore the search endpoint SQL Injection
The login bypass demonstrated authentication bypass. Now you will use a more advanced technique to extract data directly from the database.
The product search endpoint accepts a query parameter that is passed unsanitized into a SQLite query. You will use Burp Suite Repeater to craft and send a UNION SELECT attack.
- In Firefox, click the search icon at the top of the Juice Shop page.
- Search for any term (for example, apple).
- Switch to Burp Suite and click the Proxy tab.
- Click HTTP history.
- Find the GET request to /rest/products/search?q=apple in the list.
- Right-click on this request and select Send to Repeater.
- Click the Repeater tab at the top of Burp Suite to view the request.
What is Burp Repeater?
Repeater lets you take a captured HTTP request, modify it, and resend it to the server as many times as you like. This is essential for testing injection payloads because you can iterate quickly without needing to retype values in the browser each time.
Now you will craft a UNION SELECT attack. This technique appends a second query to the original, letting you read arbitrary tables. The Juice Shop product query returns 9 columns, so your injected SELECT must also return 9 columns to match.
- In the Repeater request pane, find the q= parameter in the URL line at the top of the request.
- Replace the value after q= with the following payload:
qwert')) UNION SELECT sql, '2', '3', '4', '5', '6', '7', '8', '9' FROM sqlite_master--
- Select the entire payload text you just pasted (everything after q=).
- Right-click the selected text and choose Convert selection then URL then URL-encode key characters. This converts spaces and special characters into their URL-safe equivalents.
- Click Send.
In the response pane, you should see database schema information from the sqlite_master table. This includes CREATE TABLE statements revealing every table name, column name, and data type in the database.
What does this payload do?
The qwert')) portion closes the application's original query. The search wraps input in parentheses and quotes, so the two closing parentheses and apostrophe break out of that structure.
UNION SELECT appends a second query that reads the sql column from sqlite_master. This system table stores the schema of every table in the SQLite database. The remaining columns ('2' through '9') are placeholder strings required to match the 9 columns returned by the original product search query.
- Review the response body in Repeater. Look for table definitions like Users, Baskets, and Products in the returned schema.
- Take a screenshot of the Repeater tab showing both your UNION SELECT request and the response containing the database schema.
Getting an empty or error response?
The most common issue is forgetting to URL-encode the payload. Select the entire payload text after q=, right-click, and choose Convert selection then URL then URL-encode key characters before clicking Send.
If you see a 500 error, double-check that your payload has exactly two closing parentheses and two apostrophes after qwert. The correct pattern is qwert')) not qwert').
Help me troubleshoot my UNION SELECT SQL Injection against the Juice Shop search endpoint.
You have now demonstrated three critical findings: authentication bypass via SQL Injection, hidden admin panel access via Broken Access Control, and data exfiltration via UNION SELECT. Next up, you will exploit Insecure Direct Object References to access other users' private data.
Exploit Broken Access Control and IDOR
In the previous step, you used SQL Injection to bypass authentication and extract database schema information. You now have admin-level access and a solid understanding of how the application processes user input.
This step focuses on a different class of vulnerability. Instead of injecting malicious queries, you will manipulate object references in API requests to access data belonging to other users. The application trusts that users will only request their own resources, but never actually verifies ownership.
In this step, get ready to:
- Exploit an Insecure Direct Object Reference (IDOR) in the basket API to view another user's shopping basket.
- Attempt privilege escalation by manipulating the user registration API to assign yourself an admin role.
Discover the basket API and exploit IDOR
Every user in Juice Shop has a shopping basket identified by a numeric ID. When the application fetches your basket contents, it sends a GET request to an API endpoint that includes your basket ID in the URL path. The server should verify that you own that basket before returning its contents.
- Switch back to Firefox (still proxied through Burp Suite).
- Navigate to the Juice Shop homepage at http://localhost:3000.
- Click on any product to view its details.
- Click Add to Basket to add the product to your shopping cart.
- Click the shopping basket icon in the top-right corner to open Your Basket.
This triggers a GET request to the basket API that you will now locate in Burp Suite.
- Switch back to Burp Suite.
- Click the Proxy tab, then click HTTP history.
- Scroll through the recent requests and look for a GET request to a URL containing /rest/basket/ followed by a number.
- Right-click that request and select Send to Repeater.
- Click the Repeater tab to see your request loaded in a new numbered tab.
What is the basket API endpoint?
The basket API follows the pattern /rest/basket/{id} where {id} is a numeric identifier. Your basket might be /rest/basket/1 or /rest/basket/6 depending on how many users have been created.
The vulnerability here is that the server checks whether you are logged in, but never checks whether the basket you requested actually belongs to you.
Now you will modify the basket ID to access another user's data.
- In the Repeater tab, find the basket ID number in the request URL (the number after /rest/basket/).
- Change that number to 1 (if your ID is already 1, try 2 or 3 instead).
- Click Send.
- Examine the response on the right side of the Repeater panel.
If the server returns basket contents (product names, quantities, prices) for a basket that does not belong to you, you have confirmed an Insecure Direct Object Reference vulnerability.
Why is this dangerous?
In a real application, baskets could contain sensitive information about purchasing habits, saved payment methods, or delivery addresses. An attacker could enumerate every basket by incrementing the ID (1, 2, 3, 4...) to harvest data from all users in the system.
The fix is straightforward. The server must verify that the authenticated user's session matches the owner of the requested basket before returning data.
- Try a few more basket IDs (2, 3, 4) by editing the number and clicking Send each time.
- Take a screenshot of the Repeater tab showing a modified basket ID that returned another user's basket contents.
Getting an empty response or error?
If a particular basket ID returns empty data, that basket may not have any items. Try other IDs. The admin basket (ID 1) is usually populated.
If you see a 401 or 403 error, make sure you are still logged in. Your authentication token is included in the request headers. Check that the Authorization header is present in the Repeater request.
Why can't I access another user's basket?
Escalate privileges via the user registration API
APIs that accept JSON bodies sometimes process fields that developers intended to be internal-only. If the server blindly saves whatever fields it receives, an attacker can set their own role to admin during registration.
- Switch back to Firefox.
- Click the Account menu in the top-right corner.
- Click Login.
- On the login page, click Not yet a customer? to open the registration form.
- Fill in a new registration with any email (e.g. attacker@test.com), any password, and a security answer.
- Click Register.
This registration request is now captured in Burp Suite's HTTP history. You will replay it with a modified payload.
- Switch back to Burp Suite.
- In the Proxy tab, click HTTP history.
- Look for a POST request to /api/Users.
- Right-click that request and select Send to Repeater.
- Click the Repeater tab and select the new tab containing the POST request.
You should see a JSON body containing the registration fields (email, password, security question, etc.). Now you will add a role field.
- In the request body, change the email to a new unique address (e.g. admin-escalation@test.com) so the server does not reject it as a duplicate.
- Add a new field to the JSON body: "role":"admin". Place it after any existing field, separated by a comma.
- Click Send.
- Examine the response to see whether the server accepted the role field or ignored it.
What does mass assignment mean?
This attack is called mass assignment (or parameter pollution). The API endpoint accepts a JSON object and maps every field directly to the database model without filtering. If the server does not maintain an allowlist of accepted fields, an attacker can set internal properties like role, isAdmin, or verified to arbitrary values.
The remediation is to explicitly define which fields the API accepts from user input and reject everything else.
- Take a screenshot of the Repeater tab showing your modified registration request with the "role":"admin" field and the server's response.
- Document whether the server accepted the role field (check the response JSON for a role property in the returned user object).
Request returning a 400 or 422 error?
If the email is already registered, the server rejects the request. Change the email field to a completely new address.
If you see a JSON syntax error, double-check your comma placement. Every field except the last one must be followed by a comma. Make sure no trailing comma appears after the final field before the closing brace.
Help me fix my privilege escalation request
You have now demonstrated two forms of Broken Access Control. The basket IDOR shows horizontal privilege escalation (accessing peer users' data). The registration role injection shows vertical privilege escalation (elevating your own permissions). Next up, you will exploit Cross-Site Scripting and uncover exposed sensitive files.
Exploit XSS and Security Misconfigurations
Your SQL Injection and access control exploits proved that Juice Shop's backend lacks proper input validation and authorization checks. Now you will target the client side.
Cross-Site Scripting attacks inject malicious JavaScript into a web page that other users visit. Security misconfigurations expose files and directories that should never be publicly accessible. Both are common findings on real penetration tests and rank high on the OWASP Top 10.
In this step, get ready to:
- Execute a DOM-based XSS attack through the Juice Shop search bar.
- Discover an exposed directory containing sensitive files that should be protected.
- Document both findings as evidence for your penetration testing report.
Trigger DOM-based XSS via the search function
DOM-based XSS happens when client-side JavaScript takes user input and inserts it directly into the page without sanitization. The browser then executes any embedded scripts as if the application intended them.
- In Firefox, navigate to the Juice Shop homepage at http://localhost:3000.
- Click the Search icon (magnifying glass) in the top navigation bar.
- Type a normal word like apple and press Enter.
Notice how your search term appears bolded in the results heading. The application reflects your input directly into the DOM.
- Clear the search bar and enter the following XSS payload:
<iframe src="javascript:alert(`xss`)">
- Press Enter to submit the search.
An alert box with the text "xss" should appear in Firefox. This confirms that JavaScript executed successfully through the search input.
What does this payload do?
The <iframe> tag creates an inline frame in the page. Setting its src attribute to javascript:alert(`xss`) tells the browser to execute that JavaScript code when it renders the frame.
Juice Shop uses Angular, which normally sanitizes input. However, the search component disables Angular's built-in security for displaying the search term, allowing raw HTML injection.
Why is this dangerous in the real world?
An attacker could replace the harmless alert() with code that steals session cookies, redirects users to phishing pages, or logs keystrokes. Anyone who clicks a crafted link containing the payload would be compromised.
- Take a screenshot of the alert box appearing in Firefox.
- Switch to Burp Suite and find the search request in the Proxy > HTTP history tab.
- Take a screenshot of the request showing the XSS payload in the URL parameter.
No alert box appeared?
- Make sure you are using backticks (`) around xss in the payload, not single quotes. The backtick character is on the key to the left of the 1 key.
- Confirm you typed the payload exactly as shown, including the angle brackets and the closing >.
- If Burp Suite is intercepting requests (orange "Intercept is on" button), click Forward or turn intercept off so the request reaches the server.
Still stuck? Help me troubleshoot why my XSS payload is not triggering an alert in Juice Shop.
Discover exposed sensitive files
Security misconfigurations often expose directories that developers intended to keep internal. Directory listing is a common misconfiguration where a web server displays all files in a folder when no index page exists.
- In Firefox's address bar, navigate directly to:
http://localhost:3000/ftp
A directory listing page should appear, showing a list of files with their sizes and modification dates. This directory should not be publicly accessible, but Juice Shop's server configuration serves an index of everything inside it.
What is a directory listing vulnerability?
When a web server is configured to show file indexes, anyone who guesses or discovers the path can browse its contents. Attackers find these through URL guessing, exposed links in page source, or automated scanning tools.
In production, directory listing should always be disabled. Sensitive files should be stored behind authentication or outside the web root entirely.
- Take a screenshot of the /ftp directory listing showing all exposed files.
- Note the files visible in the listing. You should see files like acquisitions.md, package.json.bak, legal.md, incident-support.kdbx, and others.
Now download a confidential file to demonstrate the impact of this misconfiguration.
- Click on acquisitions.md in the directory listing to open it.
The file opens directly in your browser. It contains planned acquisition targets marked as confidential.
Why does this file matter?
In a real company, a leaked acquisitions document could cause insider trading violations, stock price manipulation, or competitive disadvantage. The file explicitly states it is confidential and should not be distributed.
The package.json.bak file is equally dangerous. It reveals the application's entire dependency list, internal version numbers, and technology stack, giving attackers a roadmap for finding known vulnerabilities in outdated packages.
- Take a screenshot of the acquisitions.md file contents displayed in Firefox.
- Document in your notes which files are exposed and what types of sensitive data they could reveal.
Getting a 403 error on some files?
Juice Shop blocks direct access to files that do not end in .md or .pdf. This means acquisitions.md and legal.md open directly, but package.json.bak returns a 403 Forbidden error.
For this step, downloading acquisitions.md is sufficient evidence of the misconfiguration. The existence of the directory listing itself proves the vulnerability, even if some files have extension-based access controls.
Having trouble accessing the /ftp directory? Help me troubleshoot why I cannot see the Juice Shop /ftp directory listing.
You have now demonstrated two more vulnerability categories. Your XSS finding shows that client-side code execution is possible, and the exposed directory proves that the application leaks sensitive internal documents. In the next step, you will compile all of your findings into a professional penetration testing report.
Write the Pentest Report and Build Your Portfolio
You have exploited six vulnerabilities across multiple categories. Your Burp Suite history is full of evidence. Now it is time to transform those raw findings into the deliverable that actually lands you a job.
Security consultants are hired for their ability to communicate risk, not just find bugs. A professional penetration testing report shows hiring managers that you can identify vulnerabilities AND explain their business impact to non-technical stakeholders.
In this step, get ready to:
- Write a professional penetration testing report with executive summary, findings, and remediation recommendations.
- Create resume bullet points and a LinkedIn post for your cybersecurity portfolio.
Write the penetration testing report
A professional pentest report follows a standard structure that security firms use worldwide. Each finding includes proof of exploitation, a severity rating, and a remediation recommendation so the client knows exactly what to fix and in what order.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar inside the Kali VM.
- Type LibreOffice Writer and press Enter to open it.
- Create a new blank document.
Why LibreOffice Writer?
LibreOffice Writer comes pre-installed on Kali Linux and can export directly to PDF. It is the fastest way to produce a formatted report without leaving your pentest environment.
Your report needs four major sections. Build each one in order using the structure below.
Write the executive summary
The executive summary is written for non-technical stakeholders like a CTO or board member. It answers one question: how bad is it?
- At the top of your document, type a title: Penetration Test Report - OWASP Juice Shop.
- Below the title, add your name and today's date.
- Add a heading called Executive Summary.
- Write 1-2 paragraphs summarizing the engagement: what was tested, the overall risk level, and how many critical vulnerabilities you found.
Keep it non-technical
A good executive summary avoids jargon. Instead of "SQL Injection on the login endpoint," write something like "An attacker can bypass authentication entirely and gain administrator access without credentials." Focus on business impact.
Write the scope and methodology section
This section documents what was tested and how. It establishes the boundaries of your engagement so readers know exactly what is covered.
- Add a heading called Scope and Methodology.
- Document the target: OWASP Juice Shop v20.0.0 running at http://localhost:3000.
- List the tools used: Nmap (reconnaissance), Burp Suite Community Edition (proxy, interception, and request manipulation), and Firefox (browser).
- Include your testing date and testing methodology (manual black-box web application penetration test).
- Paste your Nmap scan results from earlier as evidence of the reconnaissance phase.
Write the findings section
Each vulnerability you exploited becomes a finding entry. Every finding follows the same format so the client can quickly scan severity and prioritize fixes.
- Add a heading called Findings.
- Create a subsection for each vulnerability you exploited. Use the format below for each one.
Each finding entry needs these six elements:
- Title (e.g., "SQL Injection - Authentication Bypass").
- Severity Rating (Critical, High, Medium, or Low).
- Description explaining what the vulnerability is and where it exists.
- Proof of Exploitation with your screenshots showing the attack succeeding.
- Impact Statement describing what an attacker could do with this vulnerability.
- Remediation Recommendation telling the development team how to fix it.
What severity ratings should I use?
Critical: Full authentication bypass, admin access without credentials (your SQLi login bypass). High: Access to other users' private data (IDOR on baskets), privilege escalation. Medium: Stored or reflected XSS, exposed sensitive files. Low: Information disclosure with limited impact.
Professional reports often use CVSS scores, but for your portfolio, the High/Medium/Low/Critical scale communicates risk clearly.
Write findings for each of these vulnerabilities you exploited:
- SQL Injection - Authentication Bypass (Critical). The login form accepted ' OR 1=1-- as a valid email, granting admin access. Remediate with parameterized queries.
- SQL Injection - Data Exfiltration via UNION SELECT (High). The search endpoint allowed extraction of the entire database schema. Remediate with parameterized queries and input validation.
- Broken Access Control - Hidden Admin Panel (High). The /#/administration route was accessible to any authenticated user. Remediate with server-side role checks.
- IDOR - Basket API (High). Changing the basket ID in the API request returned other users' data. Remediate with server-side ownership validation.
- Cross-Site Scripting - DOM-based XSS via Search (Medium). The search function reflected input into the DOM without sanitization. Remediate with output encoding.
- Security Misconfiguration - Exposed /ftp Directory (Medium). Sensitive files including backups and internal documents were publicly accessible. Remediate by disabling directory listing and restricting file access.
- For each finding, insert the relevant screenshot you captured during exploitation as proof.
- After all findings, add a heading called Conclusion with 1-2 paragraphs summarizing the overall security posture and prioritized next steps.
Remediation makes you stand out
Many beginner pentesters only list vulnerabilities. Including specific, actionable remediation recommendations shows employers you understand defence as well as offence. This is what separates a junior tester from a consultant.
- Click File in the LibreOffice menu bar.
- Click Export as PDF.
- Save the file to your Desktop as pentest-report-juice-shop.pdf.
Your report is now saved. Open the PDF from your Desktop to verify the formatting looks clean and all screenshots are visible.
Screenshots not showing in the PDF?
If images appear blank or broken, make sure you inserted them using Insert > Image in LibreOffice rather than pasting from the clipboard. Re-export the PDF after re-inserting any missing images.
Help me troubleshoot my LibreOffice PDF export
Create resume bullet points and LinkedIn post
Hiring managers in cybersecurity scan resumes for quantifiable achievements. They want to see what you tested, what you found, and what tools you used. A LinkedIn post amplifies your visibility to recruiters and shows you can communicate professionally about security.
- Open a new document or text file in LibreOffice Writer.
- Write 3-4 resume bullet points following the pattern: action verb + what you did + quantified result.
Here are examples of strong bullet points for this engagement:
- "Conducted a black-box penetration test against a modern web application (Node.js/Angular), identifying 6+ vulnerabilities across 5 OWASP Top 10 categories."
- "Exploited SQL Injection, XSS, IDOR, Broken Access Control, and Security Misconfiguration vulnerabilities using Burp Suite and Nmap."
- "Produced a professional penetration testing report with severity ratings, proof-of-exploitation evidence, and actionable remediation recommendations."
- "Configured a containerized testing lab using Docker, demonstrating infrastructure setup skills alongside offensive security expertise."
Why quantify your bullets?
Numbers catch a recruiter's eye. "6+ vulnerabilities across 5 categories" is far more compelling than "found several security issues." Always count your findings, tools, and categories when writing security resume bullets.
- Write your own 3-4 bullet points using the examples as a guide. Personalize them with your specific details.
- Below your resume bullets, add a heading called LinkedIn Post.
- Draft a LinkedIn post that shares what you learned without revealing specific exploit payloads or techniques that could be misused.
Your LinkedIn post should follow this structure:
- Opening hook describing the problem you solved (1-2 sentences about learning offensive security).
- What tools and methodology you used (Burp Suite, Nmap, Docker, manual testing).
- A key takeaway for the security community (what surprised you, what you learned about defence).
- A professional closing that invites conversation.
What NOT to share publicly
Never post specific payloads, exact vulnerable URLs, or step-by-step exploitation instructions on social media. Frame your post as educational and professional. Focus on methodology, tools, and lessons learned.
Good framing: "I learned how input validation prevents injection attacks." Bad framing: "Here is the exact SQL payload that bypasses authentication."
- Save your resume bullets and LinkedIn draft in the same document or as a separate file on your Desktop.
You now have three portfolio artifacts: a professional pentest report (PDF), quantified resume bullet points, and a LinkedIn post ready to publish.
Not sure if your post sounds professional?
Read it as if you were a hiring manager. Does it demonstrate skill without giving away attack details? Does it show you understand both offence and defence? If it reads like a tutorial, remove the specific technical steps and keep only the high-level methodology.
Review my LinkedIn post for professionalism
Your pentest report and portfolio materials are complete. Next up, you will push your skills further by diving into JSON Web Token manipulation in the Secret Mission.
Secret mission
JWT Manipulation and Coupon Forging
You have exploited SQL Injection, XSS, Broken Access Control, and IDOR. Now it is time to go deeper. JSON Web Tokens control session management in most modern web applications. In this secret mission, you will extract, decode, and attempt to tamper with the JWT that Juice Shop uses for authentication. Can you forge a token or crack a coupon?
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally inside your Kali VM, so there are no ongoing costs.
Resources you used:
- Docker container running OWASP Juice Shop (local, no cost).
- Burp Suite temporary project (lives in memory only, not saved to disk).
Keep everything running
No action needed. Choose this if you want to continue exploring Juice Shop challenges or practice more exploitation techniques.
- Your Docker container continues serving Juice Shop at http://localhost:3000.
- Burp Suite stays open with your full HTTP history available for review.
- No charges apply. Everything runs locally inside your Kali VM.
Pause - I'll come back to this later
Stop the running container to free up memory and CPU. You can restart Juice Shop later with the same Docker run command.
- Find your running container's name by running:
sudo docker ps
- Look for the container running the bkimminich/juice-shop image. Note its name or container ID in the NAMES or CONTAINER ID column.
- Stop the container by running:
sudo docker stop CONTAINER_NAME
- Replace CONTAINER_NAME with the actual name or ID from the previous step.
- Close Burp Suite when you are done reviewing your HTTP history.
- To restart later, run the same Docker command you used in Step 1:
sudo docker run --rm -p 127.0.0.1:3000:3000 bkimminich/juice-shop
Delete - I don't want to use this again
Remove the container and Docker image to reclaim disk space. All Juice Shop data is ephemeral and resets on every restart anyway.
- Find your running container's name by running:
sudo docker ps
- Stop the container by running:
sudo docker stop CONTAINER_NAME
- Replace CONTAINER_NAME with the actual name or ID from docker ps.
- Remove the Juice Shop Docker image to free up disk space by running:
sudo docker rmi bkimminich/juice-shop
- Close Burp Suite. Your temporary project is not saved to disk, so all captured traffic will be gone once you close the application.
- Your penetration testing report PDF, resume bullet points, and LinkedIn post are saved separately. These are your deliverables to keep.
That's a Wrap!
That's a Wrap!
Nice work! You just completed a full penetration testing engagement against a modern web application, from initial reconnaissance all the way through professional reporting.
You've learned how to:
- Build a penetration testing lab with Docker, OWASP Juice Shop, and a Burp Suite proxy chain for intercepting and manipulating HTTP traffic.
- Exploit real-world vulnerabilities across SQL Injection, Cross-Site Scripting, Broken Access Control, IDOR, and Security Misconfiguration categories using industry-standard tools and methodology.
- Produce a professional penetration testing report with an executive summary, severity-rated findings, exploitation evidence, and remediation recommendations.
- Secret Mission: Analyzed and attempted to manipulate JSON Web Tokens for privilege escalation or coupon forging.
Ready to quiz yourself?