Sitemap

A Deep Dive into a Critical Vulnerability in Clockwork

4 min readJul 24, 2025

--

Introduction

Hello, readers! Today, I want to share a fascinating journey I embarked on, uncovering a critical vulnerability in a popular PHP development tool called Clockwork. This isn’t just any story; it’s about how a seemingly small oversight can lead to significant security implications, especially in a staging environment like that of Patchstack.

Overview

Imagine you’re working late at night, digging through lines of code, and suddenly, you stumble upon something unexpected. That’s exactly what happened to me. I discovered a vulnerability that allowed unauthorized access to debugging information. This wasn’t just any information; it was the kind that could potentially expose sensitive details about the system.

The vulnerability I found was related to bypassing localhost restrictions in Clockwork. For those who might not be familiar, Clockwork is an essential tool for PHP developers, providing insights and debugging information. However, this powerful tool had a flaw that could be exploited, particularly in Patchstack’s staging environment.

Vulnerability Details

Imagine finding a backdoor in a supposedly secure building. That’s essentially what this vulnerability is like. It’s classified as an Access Control Bypass and Information Exposure, affecting specific methods within Clockwork, namely isEnabled() and hasLocalHost(). The implications are severe, with potential impacts including unauthorized access to debugging information, session hijacking, and even a full site takeover. The severity? Critical.

Technical Analysis

Clockwork’s isEnabled() Method

Clockwork has a method called isEnabled(), which acts like a gatekeeper, deciding whether Clockwork should be active based on the configuration and where the request is coming from. If the request seems to come from a trusted source, like a localhost or a common development domain, Clockwork springs into action.

public function isEnabled()
{
return $this->getConfig('enable')
|| $this->getConfig('enable') === null && $this->app['config']->get('app.debug')
&& ($this->incomingRequest()->hasLocalHost() || $this->app->runningInConsole());
}

Key Points:

  • If enable is set to true, Clockwork is enabled.
  • If enable is not set, Clockwork is enabled only if the app is in debug mode and the request seems to come from a trusted source.

Clockwork’s hasLocalHost() Method

The hasLocalHost() method is like a bouncer checking IDs. It verifies if the request's host matches common local development domains, such as localhost or 127.0.0.1.

public function hasLocalHost()
{
$segments = explode('.', $this->host);
$tld = $segments[count($segments) - 1];
return $this->host == '127.0.0.1'
|| in_array($tld, [ 'localhost', 'local', 'test', 'wip' ]);
}

Key Points:

  • The method checks if the Host header matches trusted domains.
  • This check can be tricked by crafting an HTTP request with a Host header set to a trusted domain.

Exploitation Technique

An attacker can exploit this vulnerability by:

  1. Identifying the Origin IP: Using tools to find the server’s origin IP address.
  2. Crafting a Malicious Request: Sending an HTTP request with a Host header set to a trusted domain.
  3. Accessing Clockwork Endpoint: Gaining access to sensitive debugging information.

Example Testing Using curl:

curl http://ip/__clockwork/latest -H "Host: 127.0.0.1"
  • Explanation: The Host header is set to 127.0.0.1, tricking the server into enabling Clockwork and granting access to debugging information.

Case Study: Testing Patchstack’s Staging Environment

Discovery of Patchstack’s Staging Environment

While exploring Patchstack’s infrastructure, I noticed something interesting. The production VDP API was sending a specific header in all responses, which hinted at other environments. Using this clue, I crafted a query to identify these environments:

services.http.response.headers: (key: `Access-Control-Allow-Origin` and value.headers: "*patchstack.com")
Press enter or click to view image in full size

This query led me to discover several environments, including a staging environment that became the focus of my investigation.

Scanning Patchstack Infrastructure

Using a tool called ffuf, I scanned the identified infrastructure for the Clockwork endpoint. This scan helped me pinpoint where the vulnerability could be exploited.

ffuf -w ips.txt:IP -u http://IP/__clockwork/latest -H "Host: 127.0.0.1" -mc 200

Analyzing the VDP API

The staging environment had three critical endpoints that were particularly interesting:

  1. /magic-link: Sends a unique token to a user's email for login.
  2. /login: Creates a session using the token from /magic-link.
  3. /researchers: Returns a list of researchers without requiring authentication.

Step 1: Retrieving Researcher Emails
By accessing the /researchers endpoint, I obtained a list of researchers and their email addresses. This information was crucial for understanding the potential attack surface.

Step 2: Sending a Magic Link
Using the /magic-link endpoint, I demonstrated how an attacker could send a magic link to an admin's email. This link contains a unique token for logging in.

Step 3: Extracting the Token from Clockwork Logs
Since Clockwork logs all requests and responses, I showed how an attacker could access these logs to retrieve the token sent to the admin’s email.

Press enter or click to view image in full size

Step 4: Logging in Using the Token
With the token in hand, I illustrated how an attacker could use the /login endpoint to create a session for the admin account, effectively hijacking the session.

Press enter or click to view image in full size

Step 5: Demonstrating Access to Laravel Telescope
With the admin session hijacked, I demonstrated access to Laravel Telescope, a powerful debugging tool. This tool provides detailed insights into the application’s runtime, including request data, database queries, log entries, queued jobs, and rendered views.

Press enter or click to view image in full size

--

--

0vulns 🇸🇩
0vulns 🇸🇩

Written by 0vulns 🇸🇩

eJwFgEEJAAAIxKqYxZ8wvNf1rzK-MHsRCjYCNg