Security documentation gap: naive host-based allowlist patterns allow javascript:/data: scheme bypass
- 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