Overpass API Request Sanitization in God's Eye View's Vite Middleware: 6 Security Layers Explained

God's Eye View implements a multi-stage sanitization pipeline in vite.config.js that validates POST request bodies, strips Overpass QL noise via a custom lexer, enforces strict spatial bounds on around: and bbox selectors, blocks dangerous control-flow constructs, clamps query timeouts to 25 seconds, and URL-encodes the final payload before proxying to the Overpass API.

The open-source mapping application bilawalsidhu/gods-eye-view proxies Overpass API requests through its Vite development server middleware to prevent abusive or malformed queries. This deep-dive examines the specific sanitization techniques applied to incoming requests, referencing the exact implementation lines and constants that enforce security bounds in the vite.config.js file.

How the Vite Middleware Sanitizes Overpass Requests

The sanitization logic runs inside the Vite dev server's proxy middleware, specifically within the sanitizeOverpassBody function. Each request undergoes six distinct validation stages before reaching the Overpass API backend.

1. Request Body Validation

The middleware strictly enforces POST-only access with a single data parameter containing the raw Overpass QL query. Any request missing this parameter or containing additional fields receives an immediate 400 response with the error message "Malformed query body" or "Exactly one data query is required". This prevents injection attacks through unexpected request shapes and ensures predictable payload structure.

2. Noise Stripping via stripOverpassNoise

Before parsing query logic, the raw input passes through stripOverpassNoise, a single-pass lexer implemented at lines 588-618 in vite.config.js. This function:

  • Collapses quoted string literals to empty quotes to prevent string-based evasion
  • Removes block comments (/* … */) and line comments (// …) that could hide malicious constructs
  • Guarantees comment markers inside strings cannot terminate the string early and hide malicious code

By normalizing the query text, the lexer ensures subsequent validation stages operate on the actual query semantics rather than presentation formatting.

3. Spatial Bounding Enforcement

After noise removal, the sanitizer enforces strict geographic limits at lines 636-702 to prevent planet-scale data extraction:

  • Radius limits: Any around: clause exceeding OVERPASS_MAX_AROUND_M (approximately 5 kilometers) triggers rejection with the error "Overpass around radius too large"
  • Bounding-box limits: Bbox tuples larger than OVERPASS_MAX_BBOX_DEG degrees are rejected to prevent excessive geographic coverage
  • Unbounded selector detection: Every selector must be bounded either directly via around:, bbox, is_in(), or area(), or through a previously validated set. Queries containing unbounded selectors return "Overpass query has an unbounded selector"

These checks ensure the proxy only forwards queries with deterministic, limited result sets.

4. Construct Deny-Listing

The middleware maintains a deny-list of Overpass QL constructs that could generate unbounded results or consume excessive resources. Implemented at lines 552-562, this filter blocks:

  • Control-flow constructs: foreach, complete, retro, compare, convert, and make
  • Complex filters: The poly: filter

These constructs are rejected to prevent queries that might enumerate massive object collections or perform expensive geometric operations.

5. Timeout Clamping

To prevent long-running queries from tying up server resources, the sanitizer clamps any [timeout:N] directive to OVERPASS_MAX_QL_TIMEOUT (default 25 seconds) at lines 708-712. Even if a client requests a longer timeout, the middleware overrides it with the safe maximum before forwarding.

6. Final Payload Preparation

At lines 724-733, after passing all validation stages, the sanitized query is URL-encoded and formatted as data=... for the final POST body. If any check fails, the middleware returns a 400 status with a descriptive JSON error object, preventing invalid requests from ever reaching the Overpass backend.

Client-Side Integration Example

The following JavaScript demonstrates a compliant client request that respects the middleware's sanitization requirements:

// Correct: Bounded query with proper encoding
async function getRoads(lat, lon, radius = 500) {
  const query = `
    [out:json][timeout:25];
    way(around:${radius},${lat},${lon})["highway"]["name"];
    out geom;
  `;

  const resp = await fetch('/api/overpass', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: `data=${encodeURIComponent(query)}`,
  });

  if (!resp.ok) throw new Error(`Overpass error: ${await resp.text()}`);
  return resp.json();
}

Conversely, this query would be rejected by the sanitization pipeline due to excessive radius:

// Incorrect: 60km radius exceeds OVERPASS_MAX_AROUND_M (5km)
const badQuery = `
  [out:json];
  node(around:60000,51.5,-0.1);
  out;
`;

await fetch('/api/overpass', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: `data=${encodeURIComponent(badQuery)}`,
});
// Returns: 400 Bad Request with "Overpass around radius too large"

Summary

  • Request validation enforces POST-only single-parameter bodies to prevent injection
  • stripOverpassNoise (lines 588-618) normalizes queries by removing comments and handling string literals safely
  • Spatial bounds (lines 636-702) enforce 5km radius limits, bbox degree caps, and prohibit unbounded selectors
  • Construct blocking (lines 552-562) bans resource-intensive keywords like foreach and poly:
  • Timeout clamping (lines 708-712) hard-limits execution to 25 seconds regardless of client requests
  • Safe encoding (lines 724-733) prepares the validated payload for upstream transmission

Frequently Asked Questions

What happens if a query exceeds the 5km radius limit?

The middleware returns a 400 Bad Request with the error message "Overpass around radius too large" and prevents the query from reaching the Overpass API. According to the source code at lines 636-702, any around: clause parsing to a radius greater than OVERPASS_MAX_AROUND_M triggers immediate rejection during the bounding check stage.

Why does the middleware strip comments from Overpass QL queries?

Comments are stripped via the stripOverpassNoise lexer (lines 588-618) to prevent comment-based evasion attacks where malicious code hides inside comment markers that appear to be inside string literals. By collapsing strings to empty quotes and removing both block (/* */) and line (//) comments before validation, the sanitizer ensures the subsequent security checks analyze the actual query semantics.

Which specific Overpass API constructs are blocked by the deny-list?

The middleware explicitly blocks control-flow constructs including foreach, complete, retro, compare, convert, and make, plus the poly: filter (lines 552-562). These constructs can generate large, unbounded result sets or perform computationally expensive geometric operations that would compromise server stability.

How does request sanitization improve caching behavior?

By enforcing deterministic bounds—hard-limiting timeouts to 25 seconds, capping geographic areas to 5km radii, and rejecting unbounded selectors—the middleware ensures that cached responses remain reasonably sized and fast to retrieve. According to the vite.config.js implementation, this prevents cache pollution from planet-scale queries that would otherwise evict useful, smaller result sets.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →