# How code-review-graph Implements HTTP Transport Security and Origin Guard Protection

> Learn how code-review-graph protects against cross-origin attacks using pure-ASGI origin guard. It validates Host and Origin headers, blocking unauthorized requests with a 403 response.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: deep-dive
- Published: 2026-08-15

---

**The code-review-graph repository implements a pure-ASGI origin guard that validates HTTP `Host` and `Origin` headers against loopback bindings, rejecting cross-origin requests with a 403 Forbidden response before they reach the FastMCP application.**

The `code-review-graph` project provides an optional HTTP transport layer for its Model Context Protocol (MCP) graph server. When the server binds to localhost interfaces, it activates a strict origin guard to mitigate cross-origin request forgery (CSRF) and DNS rebinding attacks. This security mechanism is implemented entirely within ASGI middleware, ensuring that untrusted browser origins cannot invoke the MCP endpoints.

## Loopback-Only Activation Strategy

The origin guard applies a **loopback-only activation policy**, ensuring that security checks only enforce same-origin policies when the server binds to local interfaces.

### Safe Host Constants

The implementation defines `LOOPBACK_HOSTS` as a frozen set of hostnames that are considered safe for local binding. This constant is defined at lines 39–40 in [`code_review_graph/http_origin_guard.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/http_origin_guard.py) and includes standard loopback identifiers such as `localhost`, `127.0.0.1`, and `::1`.

### Loopback Verification

The helper function `is_loopback_host()` determines whether a given host resolves to a loopback IP address. According to the source code at lines 45–53, this function uses Python's `ipaddress.ip_address(...).is_loopback` method to verify that the resolved IP is within the loopback range, preventing attackers from using DNS rebinding to bypass restrictions.

## Strict Header Parsing

Before validation occurs, the guard normalizes incoming request headers to eliminate ambiguity and reject malformed input.

### Host Header Normalization

The `split_host_port()` function parses the `Host` header into a normalized hostname and optional port. As implemented at lines 68–84 of [`http_origin_guard.py`](https://github.com/tirth8205/code-review-graph/blob/main/http_origin_guard.py), this function rejects malformed authorities containing spaces or forbidden characters (`/`, `\`, `?`, `#`, `@`), ensuring that only valid HTTP authorities reach the validation logic.

### Port Validation

The `_normalize_port()` helper ensures that extracted port values are valid integers within the TCP port range. Located at lines 58–66, this function validates that ports are numeric and within acceptable bounds before comparing them against the server's configured listening port.

## Origin Header Validation

The guard enforces strict scheme and authority matching on the browser-controlled `Origin` header.

### Allowed Schemes

The constant `_ALLOWED_ORIGIN_SCHEMES` restricts valid origins to `http` and `https` protocols only (lines 41–42). This prevents custom protocol schemes from bypassing security checks.

### Authority Matching

When an `Origin` header is present, the middleware validates that its authority (host and port) exactly matches the server's loopback binding. The guard rejects any request where the origin authority differs from the configured loopback host and port, effectively blocking cross-origin requests from foreign domains.

## ASGI Middleware Architecture

The `LoopbackOriginGuard` class implements the ASGI middleware protocol, wrapping the FastMCP application to intercept requests at the transport layer.

### Middleware Implementation

`LoopbackOriginGuard` is a callable ASGI middleware that inspects `scope["headers"]` before passing control to the underlying application. If the guard detects a foreign `Host` or `Origin` header that violates the loopback policy, it immediately returns a **403 Forbidden** response without invoking the FastMCP handler.

### Integration with FastMCP

The factory function `build_http_middleware(host, port)` constructs a properly configured guard instance for the FastMCP HTTP server. According to the source at lines 1155–1156, this function wires the guard into the ASGI application stack, enabling automatic protection when the server starts with loopback-specific arguments.

```python

# Build the FastMCP HTTP app with the origin guard enabled (default loopback bind)

from fastmcp import FastMCP
from code_review_graph.http_origin_guard import build_http_middleware

mcp = FastMCP("my-graph")
app = mcp.http_app(middleware=build_http_middleware("127.0.0.1", 5555))

```

```python

# Manually invoke the guard in custom ASGI setups

from code_review_graph.http_origin_guard import LoopbackOriginGuard

guard = LoopbackOriginGuard("127.0.0.1", 5555)

async def asgi_app(scope, receive, send):
    # … your ASGI endpoint …

    pass

app_with_guard = guard(asgi_app)   # Returns 403 on foreign Origin/Host

```

## Security Testing Coverage

The end-to-end test suite in [`tests/test_http_origin_guard.py`](https://github.com/tirth8205/code-review-graph/blob/main/tests/test_http_origin_guard.py) validates the guard's behavior against various attack scenarios.

### Foreign Origin Rejection

Tests at lines 56–61 verify that requests containing a malicious `Origin` header (e.g., `http://evil.example`) receive a 403 Forbidden response, confirming that the guard blocks basic cross-origin attacks.

### Same-Origin Acceptance

Lines 62–70 demonstrate that requests from the same origin, localhost variants, or requests without an `Origin` header (typical for non-browser MCP clients) succeed and reach the application handler.

### DNS Rebinding Protection

The test suite at lines 72–78 specifically targets DNS rebinding attacks, verifying that requests using a legitimate loopback IP but a forged `Host` header are rejected. This prevents attackers from using DNS rebinding to exploit the localhost binding.

## Summary

- **Loopback-only enforcement**: The `LoopbackOriginGuard` activates only when binding to loopback addresses, using `LOOPBACK_HOSTS` and `is_loopback_host()` to verify safe bindings.
- **Strict header validation**: `split_host_port()` and `_normalize_port()` parse and validate `Host` headers, rejecting malformed authorities before processing.
- **Scheme restriction**: Only `http` and `https` origins are permitted via `_ALLOWED_ORIGIN_SCHEMES`, blocking non-standard protocols.
- **ASGI middleware layer**: The guard integrates as ASGI middleware through `build_http_middleware()`, returning 403 Forbidden for violations before FastMCP processing.
- **Comprehensive testing**: [`tests/test_http_origin_guard.py`](https://github.com/tirth8205/code-review-graph/blob/main/tests/test_http_origin_guard.py) verifies protection against foreign origins, same-origin access, and DNS rebinding attacks.

## Frequently Asked Questions

### What is the primary purpose of the origin guard in code-review-graph?

The origin guard protects the optional HTTP server mode from cross-origin attacks by validating that requests originate from the same loopback binding or from trusted non-browser clients. It prevents malicious websites from invoking the MCP server when it is exposed locally via the `serve --http` command.

### How does the guard prevent DNS rebinding attacks?

The guard uses `is_loopback_host()` to resolve hostnames and verify they map to loopback IP addresses (127.0.0.0/8 or ::1) while also validating the `Host` header against the expected binding. This prevents attackers from using DNS rebinding to point a malicious domain at 127.0.0.1 and bypassing origin checks, as the guard validates both the resolved IP and the declared host authority.

### Why does the origin guard only activate on loopback addresses?

The guard specifically checks for loopback bindings because the HTTP server is intended for local development and testing. When binding to public interfaces, the project assumes proper network-level security or reverse proxying. The `LOOPBACK_HOSTS` constant and `is_loopback_host()` function ensure the middleware only enforces strict origin checking when the attack surface is limited to the local machine, avoiding false positives in legitimate cross-origin scenarios for public deployments.

### Can the origin guard be bypassed by omitting the Origin header?

No, this is by design. The guard distinguishes between browser and non-browser clients: browsers always send `Origin` for cross-origin requests, while legitimate MCP clients typically omit the header entirely. Requests without an `Origin` header are allowed (as verified in [`tests/test_http_origin_guard.py`](https://github.com/tirth8205/code-review-graph/blob/main/tests/test_http_origin_guard.py) lines 62–70), but requests with a mismatched `Origin` or `Host` header are rejected with 403 Forbidden.