Logic scanner now available! Try it out
Product - 30 min read

How ZeroPath Works

ZeroPath's methodology for identifying and resolving web app vulnerabilities, spanning common flaws to complex logic and authentication issues.

ZeroPath Team

ZeroPath Team

2024-09-21
How ZeroPath Works

ZeroPath is a Static Application Security Testing (SAST) tool that leverages LLMs to detect security vulnerabilities in your software. Developed by security engineers and successful bug bounty hunters, it identifies complex issues often missed by conventional methods, including business logic flaws, authentication vulnerabilities, and other common weaknesses. ZeroPath has been used to uncover vulnerabilities in major open-source repositories, including ones covered by bug bounty programs. By understanding code context and functionality, ZeroPath aims to provide accurate detection with fewer false positives.

The tool performs pre-merge scanning, analyzing code before it's merged into the main codebase. Pull request (PR) scans typically complete in under a minute, enabling early detection of security issues without impeding development workflows.

ZeroPath currently supports JavaScript, Python, Go, Java, C#, and PHP. It uses the tree-sitter library for Abstract Syntax Tree (AST) generation, allowing rapid integration of additional or custom language grammars.

Given the prevalence of AI in security tools, we prioritize transparency. The following sections are a rough overview of ZeroPath's functionality and present research findings.

ZeroPath Architecture and Workflow

ZeroPath's vulnerability detection process consists of six key stages, each designed to contribute to the accuracy of its findings. The following section breaks down these stages, providing a technical overview of how the system operates to identify security issues in code bases.

Triggering a Scan

ZeroPath scans can be initiated through two primary methods:

  1. Scheduled/Manual Scans

    These are initiated through the dashboard or otherwise occur at predefined intervals. They perform a more comprehensive analysis of the entire codebase, designed both to catch vulnerabilities in code that may have bypassed PR checks (e.g., direct pushes to the main branch) and refresh the intensive parts of analysis. This document describes what happens when you do a manual scan.

  2. Pull Request (PR) Scans

    PR scans are triggered automatically when a pull request is created on your repository. They are implemented as a GitHub check, which avoids using GitHub Actions minutes, and focus on analyzing only the modified code. To optimize performance, the AST from previous scans is cached, and PR scans complete in around 30 seconds on average. Only the nodes corresponding to updated code are re-parsed and integrated into the existing AST. This incremental updating approach significantly reduces processing time while maintaining high accuracy, resulting in efficient and precise scans.

Application Identification

ZeroPath starts by using AI agents to investigate what applications are inside your repository and gather some basic data about how they work. This step is crucial when dealing with mono-repositories or repositories containing multiple services, as often happens with microservice architectures. Specifically, we:

  1. Identify directory boundaries for each application
  2. Generate application descriptions and metadata, noting details like the auth procedure and tech stack
  3. Collect additional contextual information helpful for subsequent analysis stages

This process helps ensure that ZeroPath has enough information about your apps to discriminate between relevant and irrelevant security issues.

AST Generation and Indexing

To illustrate the following steps, we will be using a basic Django application that provides fundamental functionality for:

  1. User management (creating and listing users)
  2. Content management (creating and listing posts)
  3. User authentication (login and logout capabilities)

Below is an example of the method to retrieve users from the application:

class UserViewSet(View):
    def get(self, request):
        users = User.objects.all()
        return render(request, 'user_list.html', {'users': users})

That's how it's represented as plain text, but as with most languages this is broken down into an intermediate representation before compilation. Using tree-sitter we can convert the method definition into an AST that has standard names for things like "function_definition", "body", and etc.:

(function_definition
  name: (identifier)  ; get
  parameters: (parameters
    (identifier)  ; self
    (identifier))  ; request
  body: (block
    (expression_statement
      (assignment
        left: (identifier)  ; users
        right: (call
          function: (attribute
            object: (attribute
              object: (identifier)  ; User
              attribute: (identifier))  ; objects
            attribute: (identifier))  ; all
          arguments: (argument_list))))
    (return_statement
      (call
        function: (identifier)  ; render
        arguments: (argument_list
          (identifier)  ; request
          (string)  ; 'user_list.html'
          (dictionary
            (pair
              key: (string)  ; 'users'
              value: (identifier))))))))  ; users

This AST representation breaks down the get_users function, showing its structure, parameters, and the operations it performs. Each node in the tree is represented by parentheses, with the node type followed by its children. Leaf nodes (like identifiers and strings) are represented directly. Comments after semicolons provide additional information or clarification about the nodes.

This format allows for a detailed, hierarchical view of the code structure, making it easier to analyze. In particular, from the AST we create a call graph, which is a map of the program's function invocations. The call graph facilitates navigation through the codebase during vulnerability analysis, and also provides a comprehensive summary of the application's structure and behavior. This holistic understanding is key to our tool's ability to detect complex, context-dependent vulnerabilities, and it looks something like this:

graph TD
    A[WSGI Handler: process_request] --> B[URL Dispatcher: resolve]
    B --> C1[UserViewSet: dispatch]
    B --> C2[PostViewSet: dispatch]
    B --> C3[LoginView: dispatch]
    B --> C4[LogoutView: dispatch]

    C1 --> D1[UserViewSet: list]
    C1 --> D2[UserViewSet: create]
    C2 --> D3[PostViewSet: list]
    C2 --> D4[PostViewSet: create]
    C3 --> D5[LoginView: post]
    C4 --> D6[LogoutView: post]

    D1 & D2 --> E1[User.objects.all/create]
    D3 & D4 --> E2[Post.objects.all/create]
    D5 --> E3[authenticate]
    D5 --> E4[login]
    D6 --> E5[logout]

    D1 & D3 --> F1[render]
    D2 & D4 --> F2[render]

    F1 & F2 --> G[context_processor]

    D1 & D2 & D3 & D4 & D5 & D6 --> H[HttpResponse]

Graph Enrichment

After generating the AST, we enrich the graph with contextual information by identifying features like endpoints (exposed functions or URLs that can be accessed externally) and assigning attributes to each node. These attributes can be details such as request paths, HTTP methods, and authentication and authorization mechanisms. For example, a node representing a login function might be enriched with attributes indicating it uses HTTPS, accepts POST requests, and implements rate limiting. A key aspect of this enrichment is recognizing how middleware and other security controls are implemented across the application. This process transforms the basic AST into a more comprehensive representation of the application's structure and behavior. While the initial AST shows the structure of individual functions, this enriched call graph demonstrates how these functions interact and what security measures are in place throughout the application flow.

graph TD
    A[Django WSGI Handler] -->|Process Request| B[URL Dispatcher]

    %% Middleware Chain
    A -->|Pre-process| M1[Security Middleware]
    M1 -->|HTTPS Redirect| M2[Session Middleware]
    M2 -->|Manage Sessions| M3[Authentication Middleware]
    M3 -->|Authenticate User| M4[CSRF Protection Middleware]
    M4 -->|CSRF Validation| B

    %% URL Patterns and Views
    B -->|/api/users/| C1[UserViewSet]
    B -->|/api/posts/| C2[PostViewSet]
    B -->|/auth/login/| C3[LoginView]
    B -->|/auth/logout/| C4[LogoutView]

    %% View Methods
    C1 -->|GET| D1[List Users]
    C1 -->|POST| D2[Create User]
    C2 -->|GET| D3[List Posts]
    C2 -->|POST| D4[Create Post]
    C3 -->|POST| D5[Authenticate User]
    C4 -->|POST| D6[End Session]

    %% Database Interactions
    D1 & D2 -->|Query/Update| E1[User Model]
    D3 & D4 -->|Query/Update| E2[Post Model]
    E1 & E2 -->|ORM| F[Database]

    %% Template Rendering
    D1 & D3 -->|Render| G1[List Template]
    D2 & D4 -->|Render| G2[Detail Template]
    G1 & G2 -->|Apply| H[Context Processors]

    %% Static Files and Caching
    I[Static File Handler] -->|Serve| J[Static Files]
    K[Cache Middleware] -->|Cache Responses| A

    %% Response Flow
    D1 & D2 & D3 & D4 & D5 & D6 -->|Generate Response| L[Response Object]
    L -->|Process Response| M4
    M4 -->|Process Response| M3
    M3 -->|Process Response| M2
    M2 -->|Process Response| M1
    M1 -->|Process Response| A

    %% Authentication Flow
    D5 -->|Success| N[Create Session]
    D5 -->|Failure| O[Error Response]
    D6 -->|Logout| P[Delete Session]

    classDef middleware fill:#f9f,stroke:#333,stroke-width:2px;
    class M1,M2,M3,M4,I,K middleware;

Vulnerability Discovery and Validation

Finally we get to the most important part, using the call graph to discover vulnerabilities. In our application security analysis, vulnerabilities are bucketed into three main types:

  1. Technical Vulnerabilities: These encompass implementation-specific security flaws such as SQL Injection (SQLI), XML external entity (XXE) injection, Cross-site Scripting (XSS), Cross-site Request Forgery (CSRF), Leaking of secrets, and Server-side Request Forgery (SSRF).

  2. Business Logic Flaws: These vulnerabilities arise from flaws in the application's logic. Examples include:

    • Price manipulation in e-commerce systems
    • Exploitation of coupon systems leading to incorrect pricing
    • Bypassing intended workflow sequences
    • Lack of rate limiting especially when interacting with external APIs (leading to excessive charges from providers)
  3. Authentication/Authorization Issues: These stem from improper implementation of user authentication or access control mechanisms. Common subtypes include:

    • Insecure Direct Object Reference (IDOR)
    • Missing Function Level Access Control
    • Broken Session Management

Each category requires distinct analysis techniques. Technical vulnerabilities often involve pattern matching and taint analysis, business logic flaws require understanding of intended application behavior, and authentication/authorization issues necessitate comprehensive flow analysis of user sessions and permissions. Some ways we find these bugs:

  • Static Rules: ZeroPath has a large set of static rules that detail vulnerable code patterns, which are then used to semantically search if a given codebase uses them. Using this we are able to detect many existing classes of issues.
  • Threat Modeling: Having ZeroPath comes up with attack scenario and verifies them by performing rigorous investigations of the code.
  • Software Composition Analysis (SCA): ZeroPath actively monitors dependencies used within your application for known vulnerabilities, and see if these dependencies' problems are exploitable from the outside.
  • Secret Scanning and Validation: ZeroPath also scans for secrets and performs validation on the secrets to ensure that they're valid and provides information about each discovered secret to help quickly rotate and enforce best practices.

Our methodology for investigating business logic flaws and broken authentication vulnerabilities combines two AI techniques: Tree-of-Thoughts (ToT) and an adaptation of the ReAct framework.

ToT enables multi-path reasoning, intermediate step evaluation, and outcome ranking. This improves our ability to explore complex vulnerability scenarios. The ReAct-inspired component enforces structured tool usage with explicit action justification, enhancing the rigor of our investigative process.

By integrating these techniques, we've developed a framework that allows for comprehensive vulnerability assessment. ToT facilitates thorough scenario exploration, while the ReAct adaptation ensures methodical tool application. This approach has proven particularly effective in addressing the nuanced challenges presented by business logic and authentication vulnerabilities.

To further enhance our validation process and ensure the exploitability of identified vulnerabilities, ZeroPath employs a Monte Carlo Tree Self-refine (MCTSr) algorithm. This approach, inspired by recent advancements in AI problem-solving, allows us to efficiently explore and verify complex technical attack vectors.

Monte Carlo Tree Self-Refine (MCTSr)

Our MCTSr implementation builds upon research from Shanghai Artificial Intelligence Laboratory, Fudan University, and collaborating institutions. Their work on solving International Mathematical Olympiad problems using Monte Carlo Tree Search and self-refinement techniques provided a foundation that we've adapted for cybersecurity applications. We've modified this approach to navigate the decision trees involved in verifying security vulnerabilities, allowing both for more efficient exploration of potential attack vectors and fewer false positives.

The most important part of using MCTSr is defining a "win function". As a static analysis tool, our win function is implemented by an LLM that determines the chances that a hypothesized attack could work, and the severity of the problem.

The particular verification agent we use is different for problems like SSTI, SQLi, XSS, and business logic issues. Generally, an agent is designed to pull in relevant information from previous stages, and consider all of the controls that could make an attack impractical. If the LLM investigator determines that a given attack is above a given practicality threshold, it's sent for the next stage, which is patch generation and tweaking.

Patch Generation, Tweaking, and Integration

After discovering your vulnerability, we do a first pass check to see if we can fix it safely. Some vulnerabilities, like hardcoded secrets and SSRF, often require redesign and are marked unpatchable.

For issues deemed patchable, we leverage the data collected from earlier stages, leaning towards existing sanitization functions and minimal code modifications. Our validation process verifies vulnerability remediation, ensures syntactic correctness and functional preservation, and rescans to prevent new vulnerabilities. Patches failing validation undergo refinement.

Deployment methods vary: manual scans allow direct user approval and application via pull requests, while PR scans automatically create pull requests for fixes.

graph LR
    A[Patch Generated] --> B{Check Patch}
    B --> |Vulnerability Fixed| C{Check Syntax}
    C --> |Syntax Correct| D{Check Functionality}
    D --> |Functionality Unchanged| E{Rescan for New Vulnerabilities}
    E --> |No New Vulnerabilities| F{Determine Scan Type}
    F --> |Manual Scan| G[Enable User to Apply Patch]
    G --> H[Create PR for User to Merge]
    F --> |PR Scan| I[Create PR to Fix Vulnerability Automatically]
    B --> |Vulnerability Not Fixed| J[Send Back to Pipeline]
    C --> |Syntax Incorrect| J
    D --> |Functionality Changed| J
    E --> |New Vulnerabilities Found| J
    J --> A

This code generation system supports multi-file, codebase-wide changes, incorporating techniques from AutoCodeRover. It integrates with PRs, allowing developers to refine patches using natural language commands. The system can implement complex modifications across multiple files, streamlining the development process without requiring manual coding for each adjustment.

Natural Language PR Modification

Security Insights and Team Collaboration

Our tool also provides an (optional) centralized dashboard for managing application security across your organizations. It supports multi-user repository sharing, and provides visualization tools for security posture assessment and trend analysis.

Users can access repository-specific views with customizable filtering options. This feature facilitates the prioritization of high-severity issues, enabling teams to focus on the most critical security concerns within their codebase. The platform integrates with GitHub and GitLab for seamless version control interaction, and also supports direct code base uploads via zip files for projects using other version control systems or none at all.

Dashboard

Public Vulnerabilities and Research

The ZeroPath team regularly uses the tool to find new vulnerabilities in open-source projects. So far we've disclosed 11 significant vulnerabilities, including:

For a comprehensive list of our reported issues, visit our Security Wall of Fame page. Our team is actively working on responsibly disclosing its current batch of vulnerabilities, reinforcing our commitment to improving security across the open-source ecosystem.

Try ZeroPath

ZeroPath is now publicly available, with 40+ companies of various sizes already using our solution across finance, healthcare, technology, and other sectors.

Ready to see ZeroPath in action? Schedule a personalized demo to:

  • Explore key features and capabilities
  • Discuss your specific use cases
  • Get implementation and scaling insights

Ready for effortless AppSec?

Get a live ZeroPath tour.

Schedule a demo with one of the founders Dean Valentine Raphael Karger Nathan Hrncirik Yaacov Tarko to get started.