gruns / gruns/furl

Security documentation gap: naive host-based allowlist patterns allow javascript:/data: scheme bypass

Open Beginner friendly
#201 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
2.8k
Forks
165
PR merge metrics
No merged PRs in 30d

Description

## Summary

`furl` parses non-HTTP schemes (`javascript:`, `data:`, `vbscript:`, `about:`, `blob:`, `file:`) with `host=None`. This is standard-compliant parsing, but it creates a dangerous footgun: applications that use `f.host` for URL allowlisting and treat `host=None` as "safe/relative" silently accept executable schemes.

I understand this may be considered expected parsing behavior — I'm reporting it as a **documentation/hardening gap**, with a working downstream XSS/open-redirect demonstration.

## Behavior (furl 2.1.4)

```python
>>> from furl import furl
>>> f = furl("javascript:alert(document.domain)")
>>> f.scheme, f.host
('javascript', None) # naive "host is None => safe" checks pass

>>> f2 = furl("javascript://good.com/alert(1)")
>>> f2.host
'good.com' # passes host whitelists; browser still runs JS
```

## Why this matters

A very common validation pattern in downstream apps:

```python
f = furl(user_url)
if f.host in TRUSTED or f.host is None:
redirect(f.url) # or:
```

Result, verified locally with a minimal Flask app:

```bash
$ curl -i "http://127.0.0.1:5555/redirect?url=javascript:alert(document.domain)"
HTTP/1.1 302 FOUND
Location: javascript:alert(document.domain)
```

And in an HTML link context, clicking the rendered link executes `alert()` in the browser (screenshot available on request).

Tested schemes that bypass `host is None` checks: `javascript:`, `data:`, `vbscript:`, `about:`, `blob:`.
Additionally `javascript:///...` bypasses host whitelists entirely.

## Suggested mitigations

1. A prominent **SECURITY note** in the README/docs:
> Never validate URLs with `f.host` alone. Non-HTTP schemes have `host=None`.
> Always check `f.scheme in ("http", "https")` in addition to the host.

2. Optionally, a helper such as:

```python
def is_web_url(f, trusted_hosts=None):
if f.scheme not in ("http", "https"):
return False
return trusted_hosts is None or f.host in trusted_hosts
```

## Responsible disclosure note

No secret vulnerability is being disclosed — the risk is in downstream misuse of a documented-but-undocumented-risky API surface. Happy to coordinate if maintainers consider any part of this CVE-worthy (GitHub CNA can assign one if so).

Happy to provide the full PoC app and browser evidence.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reviewing the README/docs URL-validation guidance and reproduce the listed furl examples for javascript: and data: schemes. Done means adding a prominent SECURITY note that host checks alone are unsafe and that applications must restrict schemes to http/https as well as validating hosts.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
documentation, security
Issue type
Documentation
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.