Introduction

In March 2026, I passed the OSWE certification exam, part of the WEB-300 (a.k.a. AWAE) course!

The goal of this post is to give future OSWE students a clear, step-by-step plan to tackle the certification in a practical and efficient way. This isn’t a review of the OSWE. I’m assuming if you’re here, you already know what it is.

This guide starts by breaking down what it actually takes to earn the certification, the key steps involved and the main challenges you’ll run into. From there, I’ll walk through each step, explain how those challenges show up in practice, and lay out actionable ways to deal with them.

For a bit of credibility, I passed on my first attempt with a score of 100/100 after less than three months of preparation while working full-time. I also work as an Application Security Engineer, primarily focused on white-box penetration testing and source code security research. Some of the methods I share here are not only effective for the exam but also translate well to real-world white-box pentesting.

Understanding the Target

Before we can discuss how to pass the OSWE certification, we first need to break down what it actually involves. Once we understand that, we can look at where we are now, figure out what’s needed to get there, and identify the main constraints and challenges we’ll face along the way.

The Process

The OSWE exam is part of the WEB-300 course by OffSec, and the two are closely connected. The course prepares you for the exam, and the exam validates your understanding of the course material.

The course has two components:

  • Modules: Lessons on web application pentesting theory. Most use real-world vulnerabilities as case studies, explaining how they could be found and exploited. There are thirteen active modules (with four more archived).
  • Challenge Labs: CTF-style, custom-built web applications with two flags each. These mirror the exam setup. There are no walkthroughs or instructions, think of them as mock exams. There are six white-box challenge labs.

While completing the course isn’t strictly required to take the exam (unlike HTB CPTS), it’s practically necessary and will be part of this guide. If you can pass OSWE without preparation, this guide probably isn’t for you anyway.

As for the exam itself, you’re required to compromise two web applications, retrieve their flags, and develop Proof-of-Concept scripts to automate each exploit. Each application contains two flags: one obtained through in-application privilege escalation, and another gained after compromising the underlying operating system. In total, four flags.

With that in mind, the process of achieving OSWE can be broken into these phases:

  1. The warmup (optional): Get your skills to the required level.
  2. The modules: Complete all 13 active modules.
  3. The challenge labs: Complete the 6 white-box labs.
  4. The exam: Take the exam.

The Challenges

Now that we’ve broken down what it takes to earn the OSWE and split it into clear steps, the next question is: what actually makes this exam hard?

There are a lot of factors that make this a uniquely challenging certification, but these are the main ones you should keep in mind when preparing:

  • Exploitation Skills: OffSec expects you to already have OSCP-level web pentesting skills. The course won’t teach basics like what XSS is or how to use a web proxy. While it does touch on more advanced topics like prototype pollution, the coverage is fairly limited. You’re expected to fill in the gaps yourself.
  • White-box Methodology: This certification is heavily focused on testing with access to source code. Most people are used to working in a black-box setting, so this shift can be significant. White-box pentesting is a different skill set on its own, separate from just exploiting vulnerabilities.
  • Coding Skills: The exam requires you to write a reliable exploit script to automatically compromise the targets. Since AI tools aren’t allowed during the exam, you have to be comfortable writing code from scratch. On top of that, the white-box nature of the exam means you’ll spend a lot of time reading and interpreting source code.
  • Time Constraint: The exam lasts just under 48 hours. That might sound like a lot, but it’s not overly generous. If you lose time due to gaps in your preparation, it can easily be the difference between passing and failing, especially since there’s very little margin for error.

Throughout each step of this process, this guide will highlight how these challenges come into play and, more importantly, how to mitigate or work around them to stay on track.

The Steps

Step #1 - The Warmup

This first phase is about getting your baseline skills to the level needed to start studying for the exam.

This is the only optional step in this guide. Some students may already be ready and need no prep, while others will need a refresher or some skill-building before starting the OSWE path.

According to OffSec’s OSWE FAQ, students are strongly recommended to have:

  • Comfort reading and writing in at least one programming language
  • Familiarity with Linux
  • Experience with web proxies (e.g. Burp Suite)
  • General understanding of web attack vectors, theory, and practice

These requirements correspond to Exploitation Skills and Coding Skills challenges mentioned before. You need a baseline skillset to understand the WEB-300 course material.

The goal of this phase is to determine whether you meet the minimum skill level to realistically attempt the certification. If you don’t, or need a refresh, this is the time to prepare.

Exploitation Skills

For Exploitation Skills, a good benchmark is having passed OSCP or a similar certification (e.g., HTB CPTS, HTB CWES).

Specifically, I’d say you should understand the following web attacks to a non-trivial degree:

It’s normal to be more familiar with some techniques than others. For example, SSRF isn’t covered in HTB CPTS. That’s fine. The concern is if you’re not comfortable with most of these… that indicates you’re under-leveled for OSWE.

If you’re not comfortable with some of these techniques, learn them before starting WEB-300. This makes the course easier to follow and prevents basic gaps from eating into lab time, especially if you’re on the 90-day access bundle.

Fortunately, learning these techniques is straightforward. The PortSwigger Web Security Academy cover each topic. They’re free, high quality, and sufficient to bring your skills up to the required level. You’ll also gain practical experience with Burp Suite if you haven’t used web proxies before.

I’ve already linked the Web Security Academy modules for each of the web attacks, so you can browse them just by clicking.

Actionable Insight

Before starting the WEB-300 course, make sure to go through the relevant topics on PortSwigger’s Web Security Academy so you have a solid understanding of common web attacks and how web proxies work.

Coding Skills

For Coding Skills, you must be comfortable reading web application code across multiple languages and writing automation scripts before starting the WEB-300 course.

Specifically, you should be able to:

  • Read and understand non-trivial code in common web stacks
  • Follow data flow across an application (inputs → processing → outputs)
  • Write simple scripts to automate exploitation steps

Let’s start with the bad news. If you’re completely new to programming, getting to this level takes time. You’ll need to:

  • Learn core programming concepts (variables, control flow, functions, etc.)
  • Get comfortable with syntax in at least one language
  • Develop the ability to read unfamiliar codebases
  • Eventually write your own scripts (which is harder than just reading code)

On top of that, the exam expects you to read code in multiple languages, not just one.

The good news is that this gets easier over time:

  • Programming fundamentals transfer well between languages
  • Learning your second (and third) language is much faster than the first
  • Most web languages used in OSWE are relatively high-level and readable
  • The code you’ll write during the exam is usually simple and focused

If you have zero programming experience, tackling the OSWE is likely premature. You’re better off learning programming separately first, then returning once you’re comfortable. However, if you already have a basic foundation, you can bridge the gap efficiently.

For the code-writing aspect, you’ll need to create a Proof-of-Concept (PoC) exploit script during the exam. You can use any language, but Python is strongly recommended unless you’re already proficient in something else.

PoC scripts are usually straightforward. They typically involve:

  • Taking input (e.g., target URL, credentials)
  • Sending HTTP requests
  • Processing responses
  • Extracting data and chaining requests to automate exploitation

Here are some key areas to be comfortable with:

  • Command-line arguments (e.g., argparse)
  • Basic control flow (conditionals, loops)
  • HTTP requests and response handling (e.g., requests)
  • Working with WebSockets
  • File operations (reading/writing files, creating archives)
  • Encoding techniques (e.g., Base64, URL encoding)

While writing code in one language is sufficient, you’ll also need to read code across multiple languages. You should be reasonably comfortable with:

  • C# (ASP.NET)
  • Java (Spring Boot / web applications)
  • JavaScript (Node.js)
  • PHP
  • Python (Flask, Django)

It’s normal to be stronger in some languages than others. In most cases, a solid understanding of programming fundamentals is enough to navigate these ecosystems, as they share similar patterns.

If you want to practice code review, the following resources can help:

Actionable Insight

Before starting the WEB-300 course, make sure you’re comfortable reading web application code and writing simple Python scripts to automate HTTP-based workflows.

Step #2 - The Modules

Now that the warmup has been taken care of, we can start studying the WEB-300 course proper by doing each of the modules.

As of writing, there are seventeen modules in the WEB-300 course. Four of those are “archived” modules, meaning they no longer need to be studied in preparation for the exam. In practice, that leaves out thirteen modules. We’ll want to complete each one of them.

The modules do not follow the OSCP / PEN-200 format, where they are lessons about a particular technique in offensive security. Rather, they present a real vulnerability discovered in a real software product, and use it as a case study to demonstrate what a particular vulnerability is, how it can be exploited automatically using a script, and, more importantly, how it could have been found during a white-box pentest.

For this reason, this step in the plan concerns the White-box Methodology (how to find the vulnerability), Exploitation Skills (how to exploit the vulnerability), Coding Skills (how to write the PoC) challenges. It even concerns the Time Constraint aspect, as we’ll use this step to take measures that will save us time during the exam.

It’s an extremely important part of the preparation process, and the one that will take the most time. Fortunately, the plan is simple. We’ll do each module in the order they are presented and follow the instructions there. But all the while, we’ll do some specific things to address the three challenges mentioned beforehand.

Exploitation Skills

This is the most straightforward aspect to work on, but that doesn’t mean it should be taken lightly. As you go through each module, your primary goal is to fully understand the vulnerability being presented: how it works, why it exists, and what conditions make it exploitable.

Pay close attention to the exploitation process shown in the module. Try to go beyond simply following the steps: understand the reasoning behind each action, what would break the exploit, and how it might differ in a slightly altered environment. This extra layer of understanding is what will allow you to adapt during the exam instead of getting stuck when things don’t match the lab exactly.

If you encounter a vulnerability that feels unfamiliar or particularly complex, take the time to reinforce your understanding using external resources like the PortSwigger Web Security Academy, along with any other references you trust. A short detour here can save you a lot of confusion later.

Just as important as understanding is documentation. You should record each vulnerability in a way that is structured, concise, and easy to revisit under time pressure. Focus on capturing the key elements: a cheatsheet of commands to quickly copy-paste, an overview of the topic and links to any related notes on your manual.

Over time, this will evolve into your personal hacking field manual. During exams or even real-life engagements, this resource becomes invaluable.

I’ve already covered my note-taking methodology in more detail, so you can refer to my posts on Field Manuals, as well as my own public field manual for examples and inspiration.

Actionable Insight

Create a field manual and continuously update it as you progress through the modules.

Every new vulnerability or technique should be documented clearly, with the goal of making it quick to review and easy to apply during the exam.

Check my posts on the topic.

White-box Methodology

This is the area where most people will need the most improvement. The reason is simple: most aspiring cybersecurity professionals are far more accustomed to black-box scenarios.

CTFs, labs, and even certification exams tend to focus on interacting with an application from the outside. Opportunities to perform source code review or vulnerability research are much less common. Because of that, this section is going to require more deliberate effort.

Fortunately, much of the groundwork is already laid out for you in the WEB-300 course. The modules do an excellent job of walking through the inner workings of major web application technologies such as Spring Boot, ASP.NET, and Flask. Your job here is not to rediscover anything, but to absorb that knowledge and record it in a way that you can reuse later.

For each web application framework covered in the course, you should aim to document some of their details in your field manual:

  • Application entry point
  • Project structure
  • Routing mechanism
  • Request lifecycle
  • Template engine and rendering flow
  • Location of configuration files
  • How to enable verbose logging and where logs are stored

This same approach applies to database systems. You don’t need to become a database expert, but you should be comfortable with:

  • Basic query syntax
  • How to enable debug logging and where to find logs (especially useful for SQLi)
  • How the ORM interacts with the database
  • The permission model

Another highly practical addition to your notes is a collection of useful regex patterns. These are invaluable when reviewing large codebases, allowing you to quickly locate potential vulnerability sinks or interesting functionality. The course often provides some of these patterns, so make sure to capture them.

Ideally, you should organize them per language and vulnerability type. Example of vulnerabilities include:

  • SQL injection (or simply identifying query construction)
  • Insecure deserialization
  • JavaScript prototype pollution
  • XXE
  • Any other patterns you find useful

Then there’s reverse engineering. When dealing with compiled applications, you may need to recover readable source code from binaries. Tools like JD-GUI for Java or ILSpy for .NET are commonly used for this purpose. This is one of those topics that is very easy to skim through during the modules, but you shouldn’t. Reverse engineering is still in scope for the exam, so you need to be comfortable performing it when required.

The same applies to remote debugging. The labs make this process feel trivial by providing a pre-configured VSCode instance already attached to the target application. You should not rely on that convenience. If your workflow involves setting breakpoints, inspecting variables, and stepping through execution (which are all extremely powerful white-box techniques), then you must know how to replicate that setup yourself. Being able to attach a debugger to a remote process is a skill you should practice.

Finally, beyond tools and technology-specific knowledge, you should pay close attention to the methodology behind source code review. Jumping randomly between files and hoping to spot something obvious is inefficient and unreliable. Instead, you should aim to develop a structured approach: a repeatable process for navigating codebases and identifying areas of interest. The course provides guidance on this, and this guide will offer some suggestions during the challenge labs step. For now, focus on observing how the modules approach code review and start forming your own methodology.

Actionable Insight

There are several things you should do while going through the modules:

  • Record technology-specific insights (e.g. what is the significance of web.xml in Java web applications)
  • Build regex/reference tables for each vulnerability and tech stack combination (e.g. for .NET deserialization, look for XMLSerializer or BinaryFormatter)
  • Practice decompiling and reverse engineering Java and .NET binaries
  • Learn how to attach a debugger (e.g. via VSCode) to a running application process
  • Start developing a structured approach to source code review

Coding Skills

Each module that includes a case study will provide a vulnerable VM that you can spin up and interact with directly. You’ll be guided through the exploitation steps in the walkthrough, and part of that process involves reproducing the exploit yourself in the form of a PoC script.

You should do this for every single vulnerable application, even when the exploitation feels obvious or repetitive after reading the module. Skipping it because “you already understand it” is usually a mistake.

The reason is practical: writing PoCs repeatedly forces you to notice patterns in the code you’re producing. You’ll start to see the same building blocks show up again and again: HTTP request handling, payload construction, response parsing, authentication logic, and so on. These repeated components can then be put into a personal repository of reusable snippets, which becomes extremely valuable during the exam when time is limited.

As far as choice of programming languages go, Python is the most practical choice due to its simplicity and the availability of libraries for HTTP interaction and rapid scripting. I recommend that you write your PoCs in that.

A good structure is to keep your script entry point clean and explicit, using a main function that handles all user-provided inputs via command-line arguments. At minimum, you should always be able to configure the target and your own listener details without modifying the source code directly. This is important because your PoC will be executed as-is during grading, so everything must be externally configurable.

Example of main function:

import argparse
def main():
    parser = argparse.ArgumentParser(
        description="Proof-of-concept script"
    )
    parser.add_argument("target_ip", help="Target IP address")
    parser.add_argument("target_port", type=int, help="Target port")
    parser.add_argument("local_ip", help="Local IP address")
    parser.add_argument("local_port", type=int, nargs='?', default=4444, help="Local port (default: 4444)")
    args = parser.parse_args()
    
    # More stuff goes here

if __name__ == "__main__":
    main()

Beyond structure, aim to keep your scripts modular. A useful mental model is to treat your PoC as a chain of small, self-contained functions, each responsible for a single task: building requests, sending traffic, parsing responses, or processing payloads. This aligns well with a functional programming style, where you minimize shared state and side effects.

For example, instead of writing inline HTTP logic repeatedly, you might wrap it in a dedicated function that handles request creation and returns a clean response object. This makes your code easier to reuse and extend across different exploits.

HTTP request function example:

import requests
# Disable HTTPS warnings
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
def make_get_request(url):
	r = requests.get(url,verify=False)
	return r

The benefit here goes beyond readability. Over time, you’ll identify which functions you keep reusing across different PoCs, and those become prime candidates for your snippet repository. This turns exploit development mostly into a composition exercise rather than rewriting everything from scratch each time.

You can also leverage external tools or LLMs during preparation to generate and refine these snippets. Just keep in mind that this is strictly for building your toolkit beforehand! During the exam you are not allowed to use LLMs, so you should already have everything you need prepared and ready to use.

I’ve shared my own snippet repository in my public field manual, which you are free to explore. It can serve as a reference for how to structure your own, but ideally you should build and adapt your own over time so it matches your workflow.

Actionable Insight

For every module with a vulnerable application, write your own PoC script from scratch using a modular, functional approach.

As you do this repeatedly, extract recurring patterns into reusable snippets and maintain a personal snippet repository you can quickly assemble PoCs from during the exam.

Time Constraint

Some readers may have already noticed that many of the practices described so far have an important side effect: they significantly reduce the amount of time you spend during the exam itself.

Having a well-structured field manual allows you to quickly retrieve critical information, whether that’s details about specific vulnerabilities, technology stack quirks, or useful patterns to grep for during source code review. This alone can save a substantial amount of time when you’re under pressure.

In the same way, maintaining a repository of reusable code snippets becomes extremely valuable when you need to rapidly implement an exploit, such as a blind SQL injection script in Python, without having to rebuild everything from scratch. If you’ve already written and refined similar scripts during the challenge labs, you’re essentially reusing work you’ve already validated.

Actionable Insight

Once you begin the exam, time becomes one of your primary constraints.

The goal is to offload as much effort as possible to your preparation phase, so that “future you” is not solving problems from scratch under pressure.

Do not underestimate the value of a well-maintained field manual and a snippet repository.

Step #3 - The Challenge Labs

After you’re done with all the course modules, it’s finally time to move on to the challenge labs. Our goal here is to complete the challenge labs in ways that will best prepare us for the exam.

There are, as of the time of writing, seven challenge labs:

  1. Chat
  2. Erka
  3. Gallery
  4. Notebook
  5. Answers
  6. DocEdit
  7. Sqeakr

All of them are white-box engagements (you have access to the source code) except Sqeakr, which is strictly black-box. For this reason, I don’t believe it’s necessary to do Sqeakr, since this certification is about white-box first and foremost.

I’ve listed the challenge labs in order of most difficult to least difficult according to their “level” and “community rating” attributes. But in all honesty, I found them all to be of about equal difficulty. Feel free to do them in that order or in whichever order you like. What’s important is that you do them all (besides Sqeakr).

Each lab will contain one custom-written web application. Just like the exam, you will start this engagement as an anonymous user and must obtain two flags:

  1. The first flag becomes available once you exploit your way to the highest privileged access possible in the web application (typically an administrator).
  2. The second flag is on the file system of the OS the web app is running on, and can only be retrieved once you leverage some privileged feature of the web app to get unintended OS privileges in order to read the flag.

Importantly, there are two VMs in the lab, both containing the same web application. The difference is that one of them contain real flags and simulated users (if there are any) while the other does not contain flags or users, but you can SSH into it. This is for debugging purposes, and the same happens on the exam. The idea is that you find vulnerabilities and write your PoC against the debug VM and then finally test on the real VM to get the flags.

Before we move on to the strategy I recommend to streamline the engagement and make exploitation much easier, we should discuss the ways the challenge labs are NOT like the exam.

Firstly, even the most difficult challenge lab available to us is not on par with the web apps on the exam (IMO). It’s not so much that the exam targets are significantly more technically challenging (although they are harder), but rather that the exploitation chains are much longer and has many more steps. So imagine that for every flag, were this the exam there would be more steps and more hurdles to circumvent.

Secondly, the challenge lab VMs come with a web VSCode instance already attached to the web app process that you can use to read the source code and debug straight away. Don’t expect such kindness on the exam. Be prepared to decompile binaries to retrieve source code and be comfortable setting your own VSCode for remote debugging.

That being said, the challenge labs are fairly similar to the exam in all the ways that matter us for our preparation. Do your best to solve them without relying on hints or nudges. You only have so many of them to prepare, and trying them too early and spoiling will end up hurting you.

Actionable Insight

Complete all six white-box challenge labs after finishing the course modules.

Take your time and avoid using hints.

Treat them as a chance to refine your methodology, field manual, and snippet library.

White-box Methodology

This section covers what is possibly the most important part of the preparation process: how to approach a target web application methodically so you set yourself up for success. What I am going to describe is the approach I used to great effect on the exam and, at some level, on real-world white-box penetration tests.

The first thing to keep in mind is that the challenge labs are exactly that: challenge labs. They are not real software applications built primarily to serve users and avoid being exploited. Like the exam targets, they are intentionally designed to test cybersecurity knowledge and skills. That means they are vulnerable in ways that are difficult enough to be a challenge, but not so obscure that the exercise becomes unfair. Keeping this in mind lets us “game” the structure a little and gain an advantage.

Of course, this will only take you so far. You still need to research, reason about, and attack the target application in the same way you would in a real engagement. The main difference is that you should do so with a clear methodology, rather than letting the size of the codebase or the number of features overwhelm you.

Consider revisiting this section when attempting the challenge labs for the first time. It will not spoil the experience, rather, it will help guide your approach and reinforce good habits for the exam.

Initial Recon Advice

One of the biggest pitfalls in white-box penetration testing is getting overwhelmed by the amount of information available from the start. In theory, having access to the source code should make finding vulnerabilities much easier. In practice, it can make things harder if you do not have a plan.

In a typical white-box engagement, the amount of information available to you from the beginning is much greater than in a black-box assessment: source code, framework configuration, dependencies, documentation, routes, database schemas, background jobs, and so on. If your first instinct is to randomly click through files or grep for interesting strings without a specific reason, take a step back.

My advice is not to look at the source code immediately. Instead, treat the target like a black-box engagement for the first 10 to 30 minutes. In fact, do not even think of it as a security assessment at this stage. Interact with the application as a normal user. This is important because it helps you understand what the application is supposed to do before you start thinking about how to break it.

Set a timer for however long you think is appropriate, and have the discipline not to look at the source code during that time. Keep a web proxy such as Burp open so you can build a history of the HTTP requests. Explore every feature available to you, paying close attention to the HTTP and WebSocket traffic happening in the background.

While doing this, keep your note-taking tool open and record every feature or interaction you find. These are common areas worth documenting:

  • Register: Can anyone create an account, or is an invite code or email confirmation required?
  • Login: Can you enumerate existing users from error messages? Is there a “remember me” feature?
  • Password Reset: Is there a password reset flow? Does it generate a verification code or token?
  • Update Profile: Can users upload profile pictures? What does the update request look like? Are there hidden fields?
  • Posts & Comments: Note any input that may later be rendered in another user’s browser.
  • File Upload: Record anywhere you can upload files for storage, parsing, conversion, or processing.
  • Download & Export: Identify any feature that causes the browser to download something from the server. Inspect the corresponding request.

More generally, think in terms of Input → Processing → Output. Write down every interaction that follows this pattern, and also record any thoughts about where a vulnerability might exist. Do not skip this. If an idea crosses your mind, write it down, even if it seems unlikely at first.

Actionable Insight

At the start of the engagement, interact with the web application like a regular user for at least 20 minutes or so.

Write down every notable feature you find, paying close attention to Input → Processing → Output flows.

Use this phase to understand the target with curiosity and creativity. As possible attack paths come to mind, write them down for later.

Pre-Flag Advice

After spending some time interacting with the application, you should now have a rough understanding of the target, along with a number of assumptions about how it works internally and how it might be exploitable.

Once you have learned everything you reasonably can from a black-box perspective, it is time to move to the source code. The goal here is not to read the entire project from top to bottom, but rather to confirm the assumptions you have already formed and fill in the gaps that could not be understood from the outside.

Before you begin actively attacking the target, there are several aspects of the application you should understand:

  • Language: Which programming languages are used throughout the project? Are there auxiliary scripts such as Bash or PowerShell?
  • Frameworks: Which frameworks are in use? Is there a clear separation between frontend and backend components?
  • Template Engine: Are templating engines used? Are there frontend or backend protections attempting to sanitize or strip dangerous characters to prevent vulnerabilities such as XSS or SSTI?
  • Databases: Does the project use a database? Which DBMS is in use? How does the application interact with it? What tables and schemas exist?
  • Routing: Which files define the application routes? How are endpoints mapped to functions or controllers? How is access control enforced?
  • Authentication: What authentication mechanism is used? Is it cookie-based or header-based? Are tokens opaque or JWTs? How are they generated and validated?
  • Authorization: How does the application determine what a user is allowed to do? Are there roles and permissions, or are privileges tied to hardcoded assumptions such as a specific administrator account?
  • Privileged Features: What functionality becomes available to higher-privileged users that was not visible during your black-box exploration?

By selectively navigating the source code to answer these questions, you will significantly improve your understanding of the target and place yourself in a much better position to attack it effectively.

Beyond building a general understanding of the application, it is also worth quickly checking for a few common security anti-patterns. I generally advise against randomly grepping through a codebase hoping to stumble into vulnerabilities, but there are several high-value checks that are fast to perform and can sometimes reveal easy wins or useful attack paths:

  • Configuration Files: Look for files that appear configuration-related (e.g. config.py, settings.ini, .env). These often contain hardcoded credentials, API keys, or internal service information that may be retrieved via a local-file read vulnerability.
  • SQL Query Construction: If SQL queries follow a recognizable construction pattern (e.g. String sql = "...";), review every occurrence and check whether parameterized queries are consistently used.
  • Sanitization Functions: Search for custom sanitization or filtering functions. Poorly implemented filters are often bypassable and may later become useful when chained with another vulnerability.
  • Weak Random Number Generation: Many languages provide both secure and insecure random number generators (like Python’s secrets and random). Search for usage of insecure implementations and determine whether they are used in security-sensitive contexts such as token generation, password resets, or invite codes.
  • HTTP-only Cookies: If authentication is cookie-based, verify whether cookies are marked as HttpOnly. If they are not, XSS-to-session-hijacking attacks may become viable.

By this stage, you should not only have a strong understanding of the application’s attack surface, but may already have identified lower-hanging vulnerabilities worth pursuing during the flag hunt.

Actionable Insight

After completing the black-box exploration phase, spend some time studying the source code to validate assumptions and answer unresolved questions.

Also briefly look for easy wins that may hint at the intended attack path, such as hardcoded credentials or obviously flawed security controls.

1st Flag Advice

At this point, we should already have a solid understanding of the target application, along with several possible weaknesses worth investigating. Now the real attack phase begins as we pursue the first flag, also referred to as the Privilege Escalation flag.

This flag is obtained once you escalate from your initial level of access on the application (whether that is an unauthenticated user or a standard low-privileged account) to the highest privilege level available within the web application, typically an administrator. In most cases, the flag itself will appear somewhere in an administrative dashboard or another restricted area.

Metagaming

Before actively hunting for vulnerabilities, it is worth pausing for a moment to think about the “game” aspect of these labs.

The vulnerable applications used in the challenge labs and exam are intentionally structured around a two-stage progression:

  1. Escalate privileges within the web application
  2. Abuse privileged functionality to obtain RCE or arbitrary file read on the underlying operating system

Because this structure is intentional, it naturally constrains the kinds of vulnerabilities we are likely to encounter at each stage.

For example, if we are still working toward the first flag and suspect that an unauthenticated endpoint may be vulnerable to OS command injection, it is usually reasonable to deprioritize that assumption. If such a vulnerability existed at that stage, it would likely allow us to bypass the intended progression entirely and obtain both flags immediately.

Likewise, once we already control an administrator account, client-side vulnerabilities become far less relevant, since we already possess the highest level of privilege available within the application itself. At that point, our focus shifts toward vulnerabilities that can compromise the underlying operating system, such as those enabling code execution or local file access.

This style of reasoning may feel like cheesing, but thinking like this and working within the constraints of the exercise can significantly streamline things.

Because we already understand the intended progression of the labs, we can narrow down what we are actually trying to achieve during this phase.

In practice, there are only a handful of outcomes we are usually aiming for:

  • Create a New User: If account registration is restricted, we may attempt to bypass that restriction and obtain a low-privileged foothold.
  • Hijack a Privileged User: We may abuse functionality available to our controlled user to take over a more privileged account.
  • Modify Our Controlled User: A vulnerability may allow us to edit our own account and elevate its privileges.
  • Bypass Access Control: Some actions may be intended only for privileged users but improperly enforced server-side.

These outcomes are not mutually exclusive. For example, an attack chain may first involve creating a user through one vulnerability and later escalating that account through another.

What varies much more is the type of vulnerabilities that enable these goals. Below are several common patterns to keep in mind:

  • XSS to Session Hijacking: If we can force a privileged user to execute arbitrary JavaScript, we may be able to steal their session cookie and impersonate their account.
    • How: Inject HTML or JavaScript into areas likely to be viewed by administrators (e.g. comments, reports, support tickets); test whether sanitization routines are bypassable; verify whether session cookies are missing the HttpOnly flag.
  • XSS to CSRF: Even if session cookies cannot be stolen, XSS may still allow us to perform privileged actions on behalf of the victim. For example, an injected payload may silently call POST /api/admin/new and create us an administrator account.
    • How: Look for places where administrator users may render attacker-controlled content; identify privileged endpoints capable of creating or modifying users.
  • User Modification Vulnerabilities: Features that allow users to edit their profile information sometimes expose hidden or undocumented fields that can be abused for privilege escalation.
    • How: Inspect profile update requests closely; look for hidden parameters; review the corresponding backend implementation for missing authorization checks.
  • SQL Injection: If an endpoint constructs SQL queries unsafely with user input, we may inject arbitrary logic. In this stage, SQL injection is often used either to leak sensitive information (password hashes, reset tokens, OTPs) or directly modify authorization data (for example, setting an isAdmin field to true).
    • How: Identify all locations where SQL queries are dynamically constructed; determine whether user input reaches those queries unsafely; expect boolean-based or blind injection techniques to be relevant.
  • Local File Read: Some vulnerabilities may allow partial file disclosure even before administrator access is obtained. Reading sensitive local files can reveal secrets such as JWT signing keys, credentials, API tokens, or internal configuration values.
    • How: Look for vulnerabilities such as Path Traversal, LFI, or XXE.
  • Weak Secret Generation: If security-sensitive values are generated using predictable randomness, we may be able to reproduce them locally.
    • How: Identify how passwords, tokens, magic links, OTPs, invite codes, or JWT secrets are generated; determine whether insecure or deterministic RNG implementations are used.

A recurring theme during this stage is the abuse of client-side functionality and information disclosure. Vulnerabilities such as XSS, weak token generation, or file disclosure are often far more valuable during the first flag than they will be later during the OS compromise phase.

By carefully chaining together the kinds of vulnerabilities described above, we should eventually find ourselves inside an administrative interface with the first flag in view.

Actionable Insight

While pursuing the first flag, focus primarily on vulnerabilities that can increase your influence within the application.

Think in terms of privilege escalation, account takeover, information disclosure, and access control bypasses.

Use the intended structure of the labs to narrow your search space and avoid wasting time pursuing vulnerabilities that do not meaningfully advance your position.

2nd Flag Advice

Now that we control an administrator account, it is time to pursue the second flag, also referred to as the Remote Code Execution flag. In practice, this name is somewhat misleading. Unlike the first flag, this one is not displayed within the web application itself. Instead, it must be retrieved from the local file system of the target machine by abusing a vulnerability.

For that reason, this is more accurately a Local File Read flag than strictly an RCE flag. Any vulnerability that allows us to reliably retrieve the flag file (whether through command execution, arbitrary file read, or another unintended capability) should be enough.

At this stage, the scope of vulnerabilities we care about becomes much narrower. We are interested in vulnerabilities that can lead to:

  • Arbitrary file read
  • Arbitrary file write
  • Remote code execution

Additionally, these vulnerabilities will almost always exist behind privileged functionality that only administrator users can access. This significantly reduces the attack surface and helps streamline the research process.

Below are several common vulnerability patterns worth looking for during this phase:

  • Command Injection: If a privileged feature executes operating system commands unsafely with user-controlled input, we may be able to achieve command execution directly. This is one of the most reliable paths to the second flag.
    • How: Look for common command execution sinks in administrative functionality; inspect how user input is sanitized or escaped; test whether mitigations can be bypassed through encoding tricks, shell metacharacters, or alternative binaries such as those documented in GTFOBins.
  • Plugin Systems: Some applications allow administrators to upload plugins or extensions that are later loaded by the backend. If so, arbitrary code execution may be as simple as uploading a malicious plugin.
    • How: Search the source code for existing plugin examples; understand how plugins are structured, loaded, and executed; determine whether arbitrary code can be embedded into the expected format.
  • SQL Injection to RCE: Depending on the DBMS and the privileges of the database user, SQL injection vulnerabilities may allow arbitrary file reads, file writes, or even command execution.
    • How: Inspect privileged endpoints for unsafe SQL query construction; use the debug VM to determine the capabilities of the underlying database user; research DBMS-specific primitives for filesystem access or command execution.
  • Local File Inclusion: Features that dynamically load files based on user input may allow us to read arbitrary local files or, in some cases, escalate to code execution.
    • How: Look for file-loading functionality in privileged endpoints; identify whether path traversal sequences can escape intended directories; check whether uploaded files, logs, or temporary files can later be included and executed.
  • XXE: XML parsers configured insecurely may allow external entity expansion, leading to arbitrary file disclosure.
    • How: Pay close attention to privileged functionality that accepts XML or SVG uploads; inspect the parser configuration in the source code; determine whether external entities are enabled and construct payloads to retrieve local files.
  • SSTI: Features involving templates, report generation, or custom message formatting may expose server-side template injection vulnerabilities capable of code execution.
    • How: Identify features where administrators can define or customize templates; determine which template engine is in use; research the relevant payload syntax for expression evaluation or command execution.
  • Arbitrary File Write: Even without direct command execution, the ability to write files to the filesystem may still be enough to obtain RCE.
    • How: Look for privileged features capable of overwriting files or uploading content; identify scripts, cron jobs, templates, or configuration files that could be abused if modified.

Do not worry too much if you can’t find an RCE vector. If you can reliably retrieve the flag file from the target system through unintended means, that should generally be enough to satisfy the objective.

Once you obtain this second flag, you will have completed the challenge lab.

Actionable Insight

Once administrator access is obtained, narrow your focus exclusively to vulnerabilities on the new attack surface capable of achieving file read, file write, or command execution.

Prioritize privileged functionality such as plugin uploads, file processing, template rendering, export features, and any endpoint that interacts with the operating system.

At this stage, avoid getting distracted by vulnerabilities that only provide additional application-level privileges without advancing toward OS-level access.

Step #4 - The Exam

How To Know You’re Ready

If you have followed the preparation process described throughout this guide and managed to complete most (ideally all) of the white-box challenge labs with relative confidence, then you are likely ready for the exam.

The exam will still be harder than anything you encountered during the course or challenge labs, and we will discuss those differences shortly. However, by this stage, you should already have:

  • A solid understanding of the structure of the exam
  • An understanding of the four major factors that make the certification challenging
  • Familiarity with the types of vulnerabilities you are expected to identify and at what stage
  • A structured methodology for approaching white-box engagements without becoming overwhelmed
  • A growing field manual and library of reusable code snippets

As a reminder, the table below maps the major preparation milestones against the core challenges of the exam:

Milestones Exploitation
Skills
White-Box
Methodology
Coding
Skills
Time
Constraint
(Optional) Complete PortSwigger's Web Security Academy for related topics ✅
Complete all modules ✅ ✅
Write PoCs for all modules ✅
Build a reusable PoC snippet library ✅ ✅
Create a field manual for common exploitation patterns ✅ ✅
Create a field manual for white-box methodology for the major frameworks ✅ ✅
Practice decompiling binaries and remote debugging ✅ ✅
Complete all six white-box challenge labs and write PoCs ✅ ✅ ✅

If you can confidently check off most of the items above, there is little value in continuing preparations indefinitely. At some point, additional studying begins to provide diminishing returns compared to simply attempting the exam itself.

Once you reach that stage, schedule the exam and commit to it.

Last Minute Information

If you have not already done so, read the official OffSec OSWE exam guide. It is more of an information dump than a walkthrough, but these are the key details worth highlighting:

  • The exam lasts up to roughly three days:
    • 47h45m for the practical portion
    • 24h to submit the report
  • The practical exam contains two target web applications
  • Each target has a corresponding debug VM that allows SSH access
  • Each target contains two flags
  • Each flag awards a certain number of points, disclosed at the start of the exam
  • A total score of 85 points is required to pass
  • To receive points, you must submit a professional penetration test report accompanied by working PoCs demonstrating flag retrieval

Most of this should already be familiar if you carefully followed this guide. The most important detail left to discuss is the scoring model, because it leaves very little margin for error.

The structure of the exam already imposes a significant constraint: the flags on each target must effectively be obtained in sequence. If you fail to obtain the first flag on a target, you will almost certainly fail to obtain the second as well. Even if you discover the vulnerability for the second flag on the debug VM, you still need to reproduce the exploit against the real target in order to retrieve the actual flag and produce a valid PoC.

Secondly, you will also notice that the scoring leaves very little room for losing second flags. In practice, failing both second flags is generally enough to fail the exam outright, even if everything else is solved correctly.

In practice, this means:

  • You should aim to capture all four flags
  • You can afford to lose at most one second flag
  • Any worse outcome will put you below the passing score

This is not meant to create panic, only to emphasize that the exam has very limited room for mistakes.

Actionable Insight

Understand the scoring model before starting the exam and plan your time accordingly.

Treat each first flag as mandatory, since failing it will usually block progress toward the second flag on that target.

You can fail at most one of the second flags.

Last Minute Tips

At this point, you are in the final stretch: the exam itself. There is not much left to discuss that has not already been covered throughout this guide, but there are still a few practical points worth mentioning.

First of all, I will not spend much time repeating the standard advice that appears in every cybersecurity certification review: manage your time, take breaks, sleep properly, eat well, and so on. All of that is true and important, but you already know it.

What is more useful to discuss is how the dynamics of the exam differ slightly from the challenge labs. Unlike the labs, you are presented with two targets at once, and you can choose which one to tackle first.

This is more personal preference than hard advice, but when the exam starts, I recommend carefully reading the rules of engagement and briefly exploring both targets before committing to one. Look at the exposed technologies, the frameworks in use, the general feel of the application, and simply pick the one that seems more approachable or interesting to you. In the end, you will need to compromise both targets to pass anyway, but it is still nice to have some degree of control over where you begin.

Either immediately before starting the engagement or shortly after you’re done with the initial black-box exploration phase, I also recommend obtaining access to the source code and setting up your debugging workflow as early as possible. Exactly what this means will depend on your exam environment, but as mentioned previously, you should not expect the convenience of a preconfigured web VSCode instance like the challenge labs provide.

If remote debugging requires additional setup, port forwarding, IDE configuration, decompilation, or manual source reconstruction, it is better to spend the time handling that upfront rather than interrupting yourself in the middle of exploitation later.

One advantage of having two targets available simultaneously is that it gives you a natural way to reset mentally when you become stuck. If you spend too long going in circles on one target, take a break and switch to the other afterward. Coming back later with fresh eyes is often enough to notice something you missed before.

That said, I generally recommend avoiding target-switching too aggressively early on. If you obtain the first flag on a target relatively quickly, try continuing immediately toward the second flag while the application’s logic and attack surface are still fresh in your mind. Only switch once you either solve it or feel yourself slowing down and losing momentum.

Finally, there is the topic of documentation. This is extremely important.

I have already described my general reporting methodology in my HTB CPTS Reporting post. The exact process does not map perfectly to the OSWE, but some of the same principles still apply. But in all honesty, the trigger-based approach I lay out may be overkill for this exam.

Personally, I do not recommend postponing all documentation until the end of the exam. Instead, once you successfully retrieve a flag, stop and immediately stabilize your work:

  1. Clean up and finalize the PoC up to that point
  2. Ensure the exploit is reliable and reproducible
  3. Document the vulnerability discovery and exploitation steps
  4. Capture screenshots while the environment and context are still fresh
  5. Draft the relevant report sections immediately

This approach has two major benefits.

Firstly, it prevents you from forgetting important technical details several hours later when fatigue starts setting in. Secondly, it ensures that if something goes wrong later during the exam, you already have substantial portions of the report completed and validated.

Once all flags are captured, you can then focus exclusively on polishing the report into its final professional form instead of trying to reconstruct your entire thought process from memory under time pressure.

Conclusion

The OSWE is a genuinely difficult certification. The combination of white-box methodology, exploit development, source code review, and strict time pressure makes it one of the more demanding offensive security exams I took. There are very few shortcuts, and success usually comes from thorough preparation.

At the same time, the challenge is very manageable when approached methodically. If you take the time to build strong fundamentals, complete the modules carefully, practice the challenge labs seriously, and invest in your own field manual and tooling, the exam stops feeling unpredictable and starts feeling structured.

Hopefully this guide helped make that structure clearer and gave you a practical roadmap for approaching the certification with confidence.

Good luck!