Request Origin & Referer Validation#
Waline enforces access control on every API request by validating the incoming Referer or Origin header against a configured allowlist of secure domains. The gate is referrerCheck() in BaseLogic, called from the __before() hook that runs before every request. A failed check returns HTTP 403 immediately.
How referrerCheck() Works#
The method follows this decision sequence :
- No config → allow all. If
secureDomainsis not set, the check passes unconditionally. - Path whitelist.
/api/comment/rssis always allowed regardless of domain. - Build the allowlist. At runtime the allowlist is assembled from:
- Configured
secureDomainsentries localhostand127.0.0.1(hardcoded for development)- Origins of every active OAuth service fetched by the
fetch-oauth-servicemiddleware
- Configured
- Regex support. String entries wrapped in
/…/are compiled intoRegExpobjects and matched with.test(). Plain strings use strict equality. - Header preference. The check uses
referrer || origin— if aRefererheader is present it is preferred; if not, theOriginheader is used instead .
Configuration#
| Method | Detail |
|---|---|
SECURE_DOMAINS env var | Comma-separated hostnames, parsed into an array at startup |
secureDomains in code | string | RegExp | string[] | RegExp[]; overrides SECURE_DOMAINS entirely when set |
Example (env):
SECURE_DOMAINS=example.com,blog.example.com
Example (code-level, supports regex):
module.exports = Waline({ secureDomains: 'waline.js.org' });
See the server config reference for full type documentation.
OAuth Service Origins Are Auto-Allowed#
The fetch-oauth-service middleware fetches the OAuth provider list from OAUTH_URL (defaulting to https://oauth.lithub.cc) before each request and populates ctx.state.oauthServices. The referrerCheck() method then automatically appends the origin field of each service to the secure domains list . This means OAuth provider hostnames do not need to be manually added to SECURE_DOMAINS.
Known Edge Cases & Bugs#
Mobile Browsers Omit Referer During OAuth Redirect Chains#
When a mobile browser completes an OAuth flow (e.g., QQ Login), the final callback redirect comes from the OAuth provider's domain (e.g., https://ssl.ptlogin2.qq.com/jump). Mobile browsers—especially in privacy or incognito modes—frequently strip the Referer and may not send a useful Origin header either. Because referrerCheck() falls back to origin when referer is absent, and the OAuth callback origin is an external provider domain, the check fails and returns 403.
This is a confirmed open issue: users on Docker deployments with SECURE_DOMAINS set see 403 on all mobile browsers during QQ OAuth login, while desktop browsers are unaffected. Disabling SECURE_DOMAINS restores mobile login . Note that OAuth service origins are auto-allowed for the configured OAuth backend, but the browser's referer/origin during an external provider redirect chain is the provider domain, not the configured site domain — so it still fails validation.
Current workaround: Remove or comment out SECURE_DOMAINS. No code fix has been merged as of 2026-08-07.
Login Panel Redirect Mishandling (Separate Issue)#
A related but distinct bug: after email/password login, the redirect query parameter is processed by React Router's navigate(), which treats external URLs as relative paths (e.g., https://waline.example.com becomes /ui/login/https:/waline.example.com). This causes a white screen, particularly on mobile . This is not a referer validation failure — it is a client-side redirect bug in packages/admin/src/pages/login/index.jsx.
Key Files#
| File | Role |
|---|---|
packages/server/src/logic/base.js | referrerCheck() + __before() hook |
packages/server/src/config/config.js | Parses SECURE_DOMAINS env var |
packages/server/src/middleware/fetch-oauth-service.js | Populates ctx.state.oauthServices (OAuth origins) |
docs/src/en/reference/server/config.md | secureDomains config reference |