Skip to content

htaccess/no-open-redirect ​

Severity: error · Status: enforced · Applies to: ids/**/.htaccess

What ​

The hostname a redirect sends people to must be written literally in the file. Do not build it out of a value captured from the requested URL.

Why ​

A rule like this lets the visitor choose where they end up:

apache
RewriteRule ^([^/]+)/schema/(.*)$ https://service.$1/templates/$2 [R=302,L]

Request https://w3id.org/my-project/evil.example/schema/x and w3id.org redirects to https://service.evil.example/. Anyone can craft a w3id.org link that lands on a host they control, with this service's reputation behind it.

That is a phishing primitive, and a durable one — w3id.org URLs are meant to be stable for decades and are widely trusted in exactly the communities that would follow one without looking.

Using the captured value in the path is fine. It is only the hostname that matters.

Wrong ​

apache
# visitor picks the parent domain
RewriteRule ^([^/]+)/schema/(.*)$ https://service.$1/t/$2 [R=302,L]

# visitor picks the whole host
RewriteRule ^go/([^/]*)/(.*)$ https://$1/$2 [R=302,L]

# capture appended to a hostname: .evil.example makes it a different host
RewriteRule ^data(.*)$ https://files.example.org$1 [R=302,L]
apache
RewriteRule ^([^/]+)/schema/(.*)$ https://service.example.org/$1/t/$2 [R=302,L]

The hostname is fixed; the captured values go in the path.

How to fix ​

Write the destination hostname out in full. If you genuinely need to send requests to several different hosts, enumerate them:

apache
RewriteRule ^alpha/(.*)$ https://alpha.example.org/$1 [R=302,L]
RewriteRule ^beta/(.*)$  https://beta.example.org/$1  [R=302,L]

How to check ​

Run w3id-check with --rule htaccess/no-open-redirect to check this rule on its own; without it the tool runs every rule, as the pull request checks do.

sh
node tools/check/bin/w3id-check.js --rule htaccess/no-open-redirect ids/my-project

The check reasons about where the capture lands and what it can contain, so a capture whose character class cannot produce a dot or a slash — and therefore cannot change the host — is not reported.

Testing your changes covers installing the tool, and what else is worth checking by hand.

See also ​