Open source is at the core of the majority of programs that companies use, making it a prime target for hackers and bug bounty hunters. Every company runs on open source. Every dependency you trust could hide the next Log4Shell. That’s why bug bounty hunters who master open source analysis are in the front line of global cybersecurity. Discovering a vulnerability in a programming language’s framework, driver, or a widely used package such as Log4j would have a massive global impact. The infamous Log4Shell incident is a great example of how a disaster affecting hundreds of millions of systems around the world.
What Is Open Source? (Definition and Importance)
Open source refers to software whose source code is publicly available for anyone to view, use, modify, and distribute. This openness allows developers and communities around the world to collaborate, suggest new features, and improve software collaboratively through code contributions and pull requests
Open source software also plays a vital role in enhancing security and transparency. Because the code is visible to everyone, it’s easier for developers and security researchers to identify vulnerabilities, fix bugs, and strengthen overall security. This collective effort makes open source software not only more innovative but also more trustworthy and resilient over time.
Picking Your Open Source Bug Bounty Program
Choosing an open source bug bounty program should mainly be based on your interests. This helps you stay motivated and enjoy the time you spend reading source code and hunting for bugs.
There are also several other important factors to consider when selecting a target, such as:
- The programming language used
- The type of program (web, mobile, driver, framework, etc.)
- The functionality and the kind of impact that is interesting for this specific target
With all these in mind, you are ready to pick a program. You can select a wide range of different open source programs at YesWeHack and we also have a dedicated ranking for open source vulnerabilities.
Top Code Analysis Techniques
Just like any other type of security testing, code analysis can be greatly enhanced with the right tools and techniques. Code analysis tools are designed to help us efficiently scan, track, and understand code, making it easier to identify potential vulnerabilities and security issues. Broadly, code analysis can be divided into static and dynamic approaches, each with its own strengths and use cases.
Static application security testing (SAST)
Static Application Security Testing (SAST) is a technique used to identify security issues by analyzing the source code, bytecode, or binary of an application without executing it. It examines the code for patterns, unsafe coding practices, and potential vulnerabilities using methods such as data flow analysis, control flow analysis, and abstract syntax tree parsing.
Pros and Cons of Using SAST
Pros:
- Time-efficient, can scan a large amount of code quickly
- Detects common vulnerable code patterns
- Helps build a core understanding of code structure for future tools
Cons:
- Limited in detecting dynamic behavior at runtime
- Struggles to find complex issues such as business logic flaws or runtime problems like race conditions
Dynamic application security testing (DAST)
Dynamic Application Security Testing (DAST) is a technique used to identify security issues by analysing a running application. It tests the application externally by sending inputs and observing outputs, detecting vulnerabilities that occur at runtime, such as injection flaws, authentication issues, and configuration errors.
Pros and Cons of Using DAST
Pros:
- Realistic testing: Simulates real-world attacks by interacting with the application’s live environment and adapting to its behavior and logic changes.
- Effective at detecting runtime issues: Excels at uncovering vulnerabilities that only appear when the application is running.
- Reduced false positives: Focuses on actual, exploitable weaknesses rather than theoretical risks.
Cons:
- Challenging for large projects: Managing complex workflows and dependencies can make testing cumbersome in large codebases.
- Limited code insight: Identifies what is vulnerable but provides little detail about where in the source code the issue originates.
- Restricted coverage: Only analyzes code executed at runtime, leaving unreachable or untriggered paths untested.
Taint analysis
Taint analysis is a method used to check variables that can be modified by an outside user and how it moves through a program. It marks user input or other outside data as “tainted” and tracks where it goes. If that data reaches a dangerous function that for example, execute a system command or a database query without sanitizing the data first, it could lead to a serious security issue. Taint checking helps to find these weak spots more easily.
Pros and Cons of Using Taint analysis
Pros:
- Focuses on vulnerabilities where untrusted user input can influence critical parts of the application.
- Can guide fuzzers and other testing tools toward valuable sinks and potential exploitation paths.
Cons:
- May generate false positives since it analyzes many possible execution paths, not all detected flows are truly exploitable.
- Must be configured per language and framework to accurately identify sources, sanitizers, and sinks.
Control-Flow Graph (CFG)
A Control-Flow Graph (CFG) is a map that shows all the possible paths a program can take when it runs. Each point on the map represents a block of code. Making it easier to track how a program moves from one code block to another. Security researchers use CFGs to understand how a program behaves, spot dead or unreachable code, and find unusual or risky logic flows. This makes CFGs especially useful in code analysis and vulnerability research.
Pros and Cons of Using CFG
Pros:
- Provide a visual overview that helps to understand code flow
- Makes it easier to detect unreachable code
Cons:
- Becomes messy for large projects that include many complex code paths
Fuzzing
Fuzzing is a testing technique that tries to break a program by feeding it lots of random or unexpected input. The goal is to make the program crash or behave strangely, which can reveal hidden bugs or security flaws. Modern fuzzers are smart, they learn from how the program reacts and use that feedback to create even better test cases. Fuzzing is one of the most powerful ways to find real-world vulnerabilities that other testing methods might miss.
Pros and Cons of Using Fuzzing
Pros:
- Time-efficient: Can quickly detect unexpected behavior due to its high execution speed.
- Highly automated: Can run for extended periods with minimal manual intervention.
- Effective at finding unique bugs: Often discovers issues that other tools fail to detect.
Cons:
- Setup-dependent: Heavily relies on proper configuration and can be complex to set up for large or advanced codebases.
- Root cause analysis can be difficult: It may be challenging to determine the exact cause of a crash.
code analysis: Security Tools and Resources
To assist in our code analysis and security testing, tools are essential. Since we already have access to the source code of our target, we need tools to help with the heavy lifting, such as scanning for vulnerable code patterns, performing taint analysis, or simply organizing the source code to make it easier to understand.
You can also find the article we wrote where we mention the top five tools or open source testing.
Integrated development environment (IDE): Visual Studio Code (VS Code)
An IDE is your top tool and Visual Studio Code (VS Code) is for many the top choice because it is open source and supports a wide range of community based extensions. If you're familiar with web application or mobile security testing, you know that Burp Suite or Caido are the main tool. Similar, in open source code security testing, an IDE is the primary tool that allows you to analyze and debug your target's source code.
Language-specific Fuzzers
It is recommended to use a fuzzer that is tailored to the programming language you are targeting. This is because the fuzzer’s engine is designed to follow the language’s runtime execution, providing more accurate and higher-quality results.
- American Fuzzy Lop plus plus (AFL++): Native binary compiled programs (Ex: C, Golang, Rust etc...).
- Jazzer: Java bytecode (JVM execution)
- Atheris: Python bytecode (.pyc) or JIT(PyPy)
- Fuzzilli JavaScript interpreted / JIT compiled to machine code at runtime
Proxy attack tool for web and mobile applications: Burp Suite / Caido
The proxy attack will mainly be used to prove the vulnerabilities from the source code if our target is running a web application. You may have selected a bug bounty program such as OWNCloud that is a web application file sharing solution that is open source.
In that case, you also need a proxy attack tool such as Burp Suite or Caido that can intercept and modify HTTP traffic. Rather than using these tools for scanning, crawling and fuzzing. You will focus on crafting HTTP requests to test theories and perform attacks based on possible bugs you found in the source code.
GitLens as a VS Code extension: View git history
GitLens is a powerful VS Code extension that allows you to explore a project’s Git history in detail. With GitLens, you can view commits, track issues, and see which developer made specific changes.
This capability is valuable for code analysis because it helps us understand how the code has evolved over time, identify the introduction of potential vulnerabilities, and verify whether previous security issues have been properly fixed. By connecting the code changes to specific developers and commits, GitLens also makes it easier to conduct thorough audits and trace the origin of complex logic in the application.
Snyk as a VS Code extension: Detect vulnerable code dependencies
Snyk is a multi-layered static analysis and dependency scanner that allows you to analyze your code, open-source dependencies, and Infrastructure as Code (IaC) configurations.
It works by automatically analyzing your code and providing real-time feedback about:
- Vulnerable dependencies (via Snyk's Database)
- Insecure code patterns (SAST)
- Infrastructure misconfigurations in Terraform, Kubernetes, or CloudFormation files
- Container vulnerabilities
Snyk detecting vulnerabilities in source code
Snyk can be run as a standalone CLI tool but can also be integrated to VS Code using the official Snyk extension. Once we have [setup Snyk] inside VS Code, we can start scanning our source code for vulnerabilities.
We will run a Snyk code analysis vulnerability scan on the OWASP Juice Shop source code and then analyze the result. To run a scan, we can open VS Code's command palette by pressing: CTRL
+ SHIFT
+ P
in VS Code, and search for Snyk: Rescan
. A scan will start and once it is done, we will have a result which can be found in Snyk's extension tab located on the left side panel in VS Code.
As we expected, we discovered a ton of vulnerabilities in OWASP Juice shop. We can navigate through all of them by clicking on a preferred issue which will take us to the source code of the issue. A new window will appear that allow us to see the code workflow and the description of the vulnerability Snyk discovered.
We analyze the SSRF vulnerability that was discovered in the function: profileImageUrlUpload
. We can see the data flow as follows:
The function first take the user input from the HTTP POST parameter: imageUrl
, Code: if (req.body.imageUrl !== undefined) {
The value of the parameter imageUrl
is defined to the variable: url
, Code: const url = req.body.imageUrl
Finally, the code use the function fetch
using the value of the variable: url
directly without proper validations, code: const response = await fetch(url)
To prove this vulnerability, we will run OWASP Juice shop in a docker: docker pull bkimminich/juice-shop
. Then start it using: docker run --rm -p 127.0.0.1:1337:3000 bkimminich/juice-shop
. When the OWASP Juice shop start you can prove the SSRF vulnerability by sending the following raw HTTP request:
1POST /profile/image/url HTTP/1.12Host: localhost:13373Content-Type: application/x-www-form-urlencoded4Cookie: language=en; welcomebanner_status=dismiss; token=<your_session>5Content-Length: 7067imageUrl=http://127.0.0.1:3000/assets/public/images/JuiceShop_Logo.png
We can see that our profile picture successfully changed to OWASP Juice shop's logo that we fetched from localhost, proving that this SSRF is valid.
Snyk detecting vulnerable dependencies
Snyk has a large database containing known issues in dependencies, such as CVEs or packages that are malicious. Similar to how Snyk detect vulnerabilities in our own source code, Snyk scans all dependencies for known security issues and provides a detailed report of the findings.
By adding these results to our knowledge base, we can quickly detect if our target uses dependencies that are outdated or contain vulnerable packages.
CodeQL: Write advanced queries for taint and SATS analysis
CodeQL allows you to take source code and build a CodeQL database, which can then be queried using the CodeQL query language. It enables robust static application security testing (SAST) and taint analysis, helping security researchers identify potential vulnerabilities and unsafe data flows within a codebase. By representing code as a database, CodeQL supports complex analyses through structured queries, similar to SQL that can search for coding patterns and security issues across an entire project.
We won't go into detail on how to setup CodeQL since this is well documented on their official documentation on: Getting started with the CodeQL for Visual Studio Code extension. Instead, we will focus on how we can use CodeQL to improve our code analysis and security testing against source code using the offered features that CodeQL offers.
What is CodeQL queries?
CodeQL queries are the core mechanism by which you analyze source code using CodeQL. They are written in the CodeQL query language (QL), a declarative logic programming language designed to represent code as data.
A CodeQL query specifies what you want to find in a codebase rather than how to find it. Queries can range from simple searches, like listing all functions or classes, to complex analyses that track data flow, detect security vulnerabilities, or enforce coding standards. A common usage is to track user controllable input's workflow to detect the final sink that it is being used in, allowing vulnerability hunting to be more accurate.
CodeQL's database is a semantic representation of the code including its syntax, control flow, type information, and data flow relationships. Using this database, queries can detect patterns such as:
- Unsafe usage of user input (taint analysis)
- Misconfigurations or code smells
- Improper sanitization resulting in a security vulnerability
CodeQL queries to detect vulnerabilities
You can use the official CodeQL queries from the GitHub repository or write your own. The official packs contain a wide range of queries for general code quality, misconfiguration checks, and security issues mapped to CWEs.
To write your own query, follow the CodeQL documentation. As a simple example, you can list all function names in the source code you are analyzing using this QL query:
1/** * This is an automatically generated file * @name Get function names * @kind info * @problem.severity info * @id javascript/example/getfunctions */23import javascript45from Function f6select f.getName()
The query above returns all functions in the codebase (in this example, OWASP Juice Shop). The results will look similar to the screenshot below:
Example: SQL injection detection
Because CodeQL builds a database of the code (types, control flow, data flow), you can write queries that detect dataflow-based vulnerabilities such as SQL injection. The snippet below shows a focused SQLi query that uses the built-in JavaScript SQL injection flow model:
1/** * @name Database query built from user-controlled sources (SQL only) * @description Building a database query from user-controlled sources is vulnerable to insertion of * malicious code by the user. This query only checks for SQL injection flows. * @kind path-problem * @problem.severity error * @security-severity 8.8 * @precision high * @id js/sql-injection * @tags security * external/cwe/cwe-089 */23import javascript4import semmle.javascript.security.dataflow.SqlInjectionQuery as Sql56from Sql::SqlInjectionFlow::PathNode source, Sql::SqlInjectionFlow::PathNode sink7where8 Sql::SqlInjectionFlow::flowPath(source, sink)9select sink.getNode(), source, sink,10 "This SQL query depends on a user-provided string.",11 source.getNode(), "user-provided value"
By analyzing the result from the QL query we can see that a SQL injection was detected in the source code of OWASP Juice shop as displayed below:
This certainly help improve code analysis and making it easy to navigate throught how user input is being handled by the source code and in what sink it ends up in.
Organizing and track progress using the VS Code extensions: TODO Tree & Bookmarks
Besides security-focused tools, we also need tools that make it possible to structure and organize our progress. We can combine the VS Code TODO Tree and Bookmarks extensions to achieve this.
With Bookmarks, you can navigate to specific lines of code, right-click, and add a bookmark with a label. This makes it easy to return to where you left off or to mark lines that may contain potential vulnerabilities.
Similarly, Todo Tree can be used to track important code locations. To use it, navigate to the code you want to mark and add a comment containing a supported tag, such as:
1// TODO: validate filter for x function...
A useful great feature of Todo Tree is that you can customize the comment style and tags yourself. For example, you could use a custom tag like VULN
instead of TODO
, making it easier to track security-relevant notes throughout your code.
Methodology for code analysis to find security vulnerabilities
In this section, we will demonstrate a structured methodology for performing code analysis to detect security vulnerabilities. Using OWASP Juice Shop as our target, we will start from scratch and walk through each step of the process.
Setting Up Our Environment
Before we can start our code analysis, we need to properly set up our tools and target.
We’ll do this by running the target’s source code locally in Docker and creating a CodeQL database from its source code.
Start OWASP Juice Shop locally in Docker (Warning: NODE_ENV=unsafe
enable all challenges, make sure to run with `127.0.0.1` in a docker)
1docker run -it -e "NODE_ENV=unsafe" -p 127.0.0.1:1337:3000 bkimminich/juice-shop
Create a CodeQL database from the OWASP Juice Shop source code. Change: /path/to/juice-shop
to the path OWASP Juice shop has its source code.
1codeql database create juice-shop \2--threads=10 \3--language=javascript \4--command="npm i" \5--source-root="/path/to/juice-shop";
Open OWASP Juice Shop's source code in VS Code
1cd /path/to/juice-shop && code .
Start and create a project in our Proxy attack tool (Burp, Caido, Zap etc...)
Performing code analysis against OWASP Juice shop
We can now begin our code analysis of OWASP Juice Shop. Below we'll illustrate a realistic scenario that applies our methodology to identify vulnerabilities in the code and validate them using our proxy attack tool.
Because Juice Shop is intentionally vulnerable, tools like Snyk will immediately report many issues, that’s expected. We could investigate and exploit all of those findings (as we would on a real application), but for this exercise we’ll go deeper: we’ll use CodeQL to write custom queries that reveal the code workflows that lead to vulnerabilities, then verify the vulnerabilites we discover through our attack proxy (Ex: Burp Suite).
Creating our very first CodeQL query to discover user controllable data:
1/** * @name Taint remote sources * @description Sources of untrusted user input. * @kind problem * @problem.severity info * @id javascript/example/taint-remote-sources * @tags summary * @precision medium */23import javascript4import semmle.javascript.dataflow.TaintTracking56from RemoteFlowSource node7select node, node.getSourceType()
TaintTracking (semmle.javascript.dataflow.TaintTracking
) Provides classes for performing customised taint tracking. We then take all the remote flow sources (RemoteFlowSource
) which is input coming from an outside user and get the source of it using the function: getSourceType
.
We now have an understanding of what we can control in the application. Let's dig deeper and analyze the variables that we can control.
When reviewing the variables we control, we found that the file
parameter in the handleZipFileUpload
function is attacker‑controllable. Further examination shows the code appears vulnerable to a Zip Slip vulnerability. It extracts a ZIP archive and writes its contents to disk without properly sanitizing the filenames inside the archive. An attacker can include ../
(dot‑dot‑slash) sequences in filenames to do a path traversal and overwrite arbitrary system files.
If we continue to analyse the code, by checking the functions references in VS Code by right clicking on the function and then click: Find All References
(SHIFT
+ ALT
+ F12
). We can see that this function is being used in the file: server.ts
, in the web route: /file-upload
.
Finally, if we perform a global seach in VS Code (CTRL
+ SHIFT
+ F
), we discovered that the endpoint: /file-upload
is within an Angular component.
Verifying and Exploiting a Potential Vulnerability: Zip Slip
We now have the information that we need and can test our theory to exploit this Zip Slip vulnerability. We can access the OWASP Juice shop's endpoint in our browser that has the upload feature at: http://localhost:1337/#/complain
.
Before we upload anything, we will create a zip file that can be used to exploit the Zip Slip vulnerability, we will use the tool: https://github.com/avlidienbrunn/archivealchemist, developed by: avlidienbrunn.
To discover the correct system path that we wish our file to be uploaded to (Ex: /ftp
on the web server), we can go back to the code and make a global search looking for anything related to: ftp/
.
We can quickly spot the system path for the ftp
in the Dockerfile
:
To create our zip file, we will use the following command:
1archive-alchemist zipslip.zip add "../../../../../../juice-shop/ftp/pwned.txt" --content "pwned!"
This will make a zip file that contains the filename: ../../../../../../juice-shop/ftp/pwned.txt
with the content pwned!
. If we successfully exploit the Zip Slip vulnerability, it should write the file: pwned.txt
.
We now add a random message as: zipslip and upload our zip file.
To confirm that the web application is vulnerable we will navigating to the endpoint: http://localhost:1337/ftp
which will list our file if successful.
We can see our file: pwned.txt
, proving that this web application indeed is vulnerable to a Zip Slip vulnerability and that it is exploitable.
Responsible Disclosure: How to Report Your Discovered Bugs
Once you have discovered and verified a valid security vulnerability, by safely reproducing or exploiting it as described earlier, you are ready to write and submit your bug bounty report.
Start by finding the bug bounty program of your target. You can browse through all bug bounty programs on YesWeHack to find the program page. After finding your program, click “Submit Report.” From there, you can begin writing your report, explaining step-by-step how you found the vulnerability, the type of vulnerability it is, which part of the source code is affected, and providing a clear proof of concept that demonstrates how the issue can be exploited.
Finally, describe the impact of the vulnerability and offer recommendations for mitigation. This helps the security team understand the severity and fix it more efficiently, and is much appreciated.
If you want to learn how to write a professional, well-structured bug bounty report, we’ve created a detailed guide just for you: How to write an effective Bug Bounty report.
Conclusion: Ethical Impact and Next Steps
Open source software powers the modern internet and your research helps keep it safe. Every vulnerability you discover and report responsibly protects millions of users worldwide.
Use the techniques you’ve learned from code analysis and fuzzing to Snyk, CodeQL, and DAST to uncover real security flaws. Always validate in safe environments, document your findings clearly, and submit professional bug bounty reports that explain how the issue works together with a proof of concept and its impact.
Responsible disclosure isn’t just good ethics, it’s what turns your skills into real-world impact. By staying ethical, following program scopes, and collaborating with maintainers, you help make open source stronger, safer, and more trusted.
Stay curious. Keep testing. And keep hacking for good.
References
- https://code.visualstudio.com/
- https://owasp.org/www-project-juice-shop/
- https://codeql.github.com/
- https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-codeql
- https://docs.snyk.io/developer-tools/snyk-ide-plugins-and-extensions/visual-studio-code-extension
- https://code.visualstudio.com/docs/debugtest/debugging
- https://www.yeswehack.com/news/yeswehack-authorised-cve-numbering-authority
- https://yeswehack.com/programs?scopeType%5B%5D=open-source