Report on security risks of exposing a tunneled webapp

Date: 2025 06-June 27

Clayton 0:

Shared index html for https://api.pavlov3d.world

AI 0:

Thanks for sharing your index HTML! This helps identify the attack surface exposed by your live plotting frontend. Here’s a focused rundown of what info in this page and its behavior could potentially be leveraged maliciously:


What Info Could Be Leveraged Maliciously From This Frontend?

1. The /data Endpoint

2. Data Structure & Labels

3. Frontend Exposure

4. No Authentication or Authorization Visible


What To Do To Harden This


Summary

The biggest concern is that anyone with the URL can access /data and the live data feed freely, scraping or abusing it.

By itself, the HTML isn’t revealing passwords or secrets, but combined with your backend config and access control (or lack thereof), it can be leveraged for:


If you want, I can help draft a minimal Flask or FastAPI auth layer you could plug in to protect the /data endpoint and the web app? Or help configure Cloudflare Access or API gateway policies?


Clayton 1:

I am most interested in

Talk about the theory. if you share snippets, use fastapi.

AI 1:

Got it! Let’s dive into the theory behind rate limiting and CORS policies, then I'll show you how those map into FastAPI with minimal example snippets.


1. Rate Limiting Theory

What is Rate Limiting?

Rate limiting controls how many requests a client (identified usually by IP or API key) can make to your API in a given time frame (e.g., 100 requests per minute). This protects your backend from:

How Does It Work?

Common Implementations


2. CORS Policy Theory

What is CORS?

Cross-Origin Resource Sharing (CORS) is a security feature in browsers that restricts web pages from making requests to a different domain than the one serving the page — unless the server explicitly allows it.

Why is CORS Important Here?

Your frontend is fetching /data — if the web app is served from domain A and the API is on domain B (or a different port), browsers will block the requests unless CORS is properly configured.

How to Secure CORS?


FastAPI Implementation Examples

a) Rate Limiting with FastAPI

FastAPI does not have built-in rate limiting, but you can use third-party libraries like slowapi (built on limits) or implement a simple in-memory rate limiter.

Here’s a minimal example using slowapi:

from fastapi import FastAPI, Request, HTTPException
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded

app = FastAPI()

# Initialize limiter: 5 requests per minute per IP
limiter = Limiter(key_func=get_remote_address, default_limits=["5/minute"])
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

@app.get("/data")
@limiter.limit("10/minute")  # Specific rate limit on this route
async def get_data(request: Request):
    # Your data retrieval logic here
    return {"x": [1, 2, 3], "y": [4, 5, 6]}

b) CORS Configuration with FastAPI

FastAPI uses fastapi.middleware.cors.CORSMiddleware.

Example allowing only your domain:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "https://yourdomain.com",  # Replace with your actual frontend domain
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # Only allow your frontend domain
    allow_credentials=True,
    allow_methods=["GET", "POST"],  # Restrict to only needed methods
    allow_headers=["*"],  # Or specify specific headers if needed
)

@app.get("/data")
async def get_data():
    # Your API logic here
    return {"x": [1, 2, 3], "y": [4, 5, 6]}

Summary

Feature Purpose FastAPI Implementation
Rate limiting Protect /data from excessive calls Use slowapi or custom logic with decorators or middleware
CORS policy Restrict frontend access to trusted origins Use CORSMiddleware to whitelist your frontend domain

If you want, I can help you craft a minimal FastAPI app with both these protections integrated, ready to plug into your existing backend.

Clayton 2:

right now cloudflared is tunneling to a public subdomain. can i instead tunnel to a priviate subdomain set up on an AWS server, and then from there tunnel to he public subdomain?

The purpose of this: the initial server needs to be secure. It is on the network necessary to access the source of the data. I need to pass the data, via API or tunneling, to a system that is accesible.

This was, the initial in-house server doesn't need to see all of the traffic for the public subdomain when people visit the web app, it is only passing the data feed to the system that will host the public web app and see the traffic

AI 2:

Yes — what you're describing is a proxy or relay architecture, where:

This is a good practice for isolating secure infrastructure. Let's break it down and discuss your architecture and how to implement it.


🔐 Problem Context

You want:


✅ Architecture Overview

[SECURE INTERNAL NETWORK]
┌────────────────────────┐
│ Internal Server        │
│ - Access to raw EDS    │
│ - FastAPI or script    │
│ - Sends JSON feed      │
└────────┬───────────────┘
         │ (pull or push)
         ▼
[DMZ or AWS SERVER]
┌────────────────────────┐
│ AWS EC2                │
│ - Receives data        │
│ - Hosts live web app   │
│ - Has public Cloudflare|
│   tunnel to subdomain  │
└────────┬───────────────┘
         │
         ▼
[CLIENT DEVICES]
- Access app via
  `https://your-tunnel.cloudflare.com`

🔧 Implementation Options

✅ Option 1: Push from Internal to AWS

Internal Server:

AWS Server:

➡️ Pros:

➡️ Cons:


✅ Option 2: Cloudflare Tunnel from Internal to AWS

You can run a Cloudflare Tunnel from the internal server to AWS, allowing the AWS instance to fetch() data from the internal system via its private tunnel address.

This is zero trust style:

➡️ Pros:

➡️ Cons:


🔐 Security Benefits


⚙️ FastAPI Example (AWS Server)

# AWS Server: receives data
from fastapi import FastAPI, Request

app = FastAPI()
latest_data = {}

@app.post("/api/feed")
async def receive_feed(request: Request):
    global latest_data
    latest_data = await request.json()
    return {"status": "ok"}

@app.get("/data")
async def serve_data():
    return latest_data

Internal server script (pusher):

import requests
import time

def push_data():
    while True:
        data = get_fresh_data_somehow()
        requests.post("https://aws-your-domain/api/feed", json=data)
        time.sleep(2)

push_data()

🧱 Recommendation

If you want minimal moving parts and the internal server is allowed to make outbound HTTPS:

If you want true zero trust, or can't push but can tunnel out:


Want help setting up either route (e.g., using cloudflared access, FastAPI relay, or adding authentication)?